@zoho_apptics/apptics-js-sdk 2.0.0-beta → 2.0.0-beta.2

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 (236) hide show
  1. package/CHANGELOG.md +191 -21
  2. package/README.md +519 -333
  3. package/dist/apptics.esm.min.js +2 -2
  4. package/dist/apptics.esm.min.js.map +1 -1
  5. package/dist/apptics.min.js +2 -2
  6. package/dist/apptics.min.js.map +1 -1
  7. package/dist/chunks/lifecycle-C6m1W7jo.min.js +3 -0
  8. package/dist/chunks/lifecycle-C6m1W7jo.min.js.map +1 -0
  9. package/dist/chunks/send-CgUO82ne.min.js +3 -0
  10. package/dist/chunks/send-CgUO82ne.min.js.map +1 -0
  11. package/dist/cjs/core/attempts.js +1 -1
  12. package/dist/cjs/core/batch.js +2 -2
  13. package/dist/cjs/core/consent.d.ts +18 -4
  14. package/dist/cjs/core/consent.js +31 -15
  15. package/dist/cjs/core/constants.d.ts +57 -27
  16. package/dist/cjs/core/constants.js +52 -33
  17. package/dist/cjs/core/db.d.ts +12 -4
  18. package/dist/cjs/core/db.js +167 -34
  19. package/dist/cjs/core/debug.js +1 -1
  20. package/dist/cjs/core/env.d.ts +0 -3
  21. package/dist/cjs/core/env.js +1 -9
  22. package/dist/cjs/core/framework-id.d.ts +1 -1
  23. package/dist/cjs/core/framework-id.js +3 -3
  24. package/dist/cjs/core/guard.d.ts +9 -0
  25. package/dist/cjs/core/guard.js +27 -13
  26. package/dist/cjs/core/hooks.d.ts +7 -4
  27. package/dist/cjs/core/hooks.js +3 -3
  28. package/dist/cjs/core/locks.d.ts +9 -0
  29. package/dist/cjs/core/locks.js +22 -0
  30. package/dist/cjs/core/logger.d.ts +3 -4
  31. package/dist/cjs/core/logger.js +4 -40
  32. package/dist/cjs/core/state.d.ts +9 -6
  33. package/dist/cjs/core/state.js +3 -5
  34. package/dist/cjs/core/storage.d.ts +20 -5
  35. package/dist/cjs/core/storage.js +115 -20
  36. package/dist/cjs/core/stylesheet.d.ts +8 -0
  37. package/dist/cjs/core/stylesheet.js +29 -0
  38. package/dist/cjs/core/transport.d.ts +2 -0
  39. package/dist/cjs/core/transport.js +30 -18
  40. package/dist/cjs/core/utils.js +1 -1
  41. package/dist/cjs/core/validate.js +2 -2
  42. package/dist/cjs/device/appversion.d.ts +10 -6
  43. package/dist/cjs/device/appversion.js +38 -3
  44. package/dist/cjs/device/index.d.ts +28 -2
  45. package/dist/cjs/device/index.js +312 -44
  46. package/dist/cjs/engagement/api-rules.d.ts +32 -67
  47. package/dist/cjs/engagement/api-rules.js +144 -157
  48. package/dist/cjs/engagement/auto-api.js +2 -2
  49. package/dist/cjs/engagement/auto-screen.d.ts +2 -0
  50. package/dist/cjs/engagement/auto-screen.js +67 -3
  51. package/dist/cjs/engagement/defined-events.js +1 -1
  52. package/dist/cjs/engagement/send.js +12 -3
  53. package/dist/cjs/engagement/session.d.ts +29 -3
  54. package/dist/cjs/engagement/session.js +253 -26
  55. package/dist/cjs/engagement/track.d.ts +4 -4
  56. package/dist/cjs/engagement/track.js +58 -30
  57. package/dist/cjs/errors/send.js +2 -2
  58. package/dist/cjs/errors/track.d.ts +2 -1
  59. package/dist/cjs/errors/track.js +49 -7
  60. package/dist/cjs/feedback/controls.d.ts +12 -0
  61. package/dist/cjs/feedback/controls.js +104 -25
  62. package/dist/cjs/feedback/index.d.ts +8 -7
  63. package/dist/cjs/feedback/index.js +32 -13
  64. package/dist/cjs/feedback/logs.d.ts +13 -11
  65. package/dist/cjs/feedback/logs.js +57 -28
  66. package/dist/cjs/feedback/quartz.d.ts +18 -0
  67. package/dist/cjs/feedback/quartz.js +105 -0
  68. package/dist/cjs/feedback/send.d.ts +5 -2
  69. package/dist/cjs/feedback/send.js +30 -28
  70. package/dist/cjs/feedback/styles.d.ts +10 -0
  71. package/dist/cjs/feedback/styles.js +8 -0
  72. package/dist/cjs/feedback/template.d.ts +1 -1
  73. package/dist/cjs/feedback/template.js +20 -12
  74. package/dist/cjs/feedback/ui.d.ts +21 -6
  75. package/dist/cjs/feedback/ui.js +283 -70
  76. package/dist/cjs/heatmap/send.d.ts +2 -0
  77. package/dist/cjs/heatmap/send.js +3 -5
  78. package/dist/cjs/heatmap/track.d.ts +1 -1
  79. package/dist/cjs/heatmap/track.js +87 -16
  80. package/dist/cjs/index.d.ts +16 -63
  81. package/dist/cjs/index.js +144 -95
  82. package/dist/cjs/lifecycle.d.ts +21 -3
  83. package/dist/cjs/lifecycle.js +353 -89
  84. package/dist/cjs/remoteconfig/country.d.ts +4 -0
  85. package/dist/cjs/remoteconfig/country.js +73 -0
  86. package/dist/cjs/remoteconfig/custom.d.ts +7 -7
  87. package/dist/cjs/remoteconfig/custom.js +31 -51
  88. package/dist/cjs/remoteconfig/evaluate.d.ts +3 -3
  89. package/dist/cjs/remoteconfig/evaluate.js +56 -43
  90. package/dist/cjs/remoteconfig/fetch.d.ts +16 -9
  91. package/dist/cjs/remoteconfig/fetch.js +120 -39
  92. package/dist/cjs/remoteconfig/index.d.ts +19 -8
  93. package/dist/cjs/remoteconfig/index.js +81 -39
  94. package/dist/cjs/remoteconfig/store.d.ts +15 -7
  95. package/dist/cjs/remoteconfig/store.js +68 -35
  96. package/dist/cjs/remoteconfig/tz-countries.d.ts +8 -0
  97. package/dist/cjs/remoteconfig/tz-countries.js +13 -0
  98. package/dist/{esm/core → cjs/remotelog}/callsite.d.ts +11 -4
  99. package/dist/cjs/{core → remotelog}/callsite.js +30 -7
  100. package/dist/cjs/remotelog/gate.d.ts +2 -11
  101. package/dist/cjs/remotelog/gate.js +9 -35
  102. package/dist/cjs/remotelog/index.d.ts +4 -21
  103. package/dist/cjs/remotelog/logger.d.ts +11 -17
  104. package/dist/cjs/remotelog/logger.js +31 -59
  105. package/dist/cjs/remotelog/send.js +11 -11
  106. package/dist/cjs/remotelogger/index.d.ts +12 -0
  107. package/dist/cjs/remotelogger/index.js +18 -0
  108. package/dist/cjs/scheduler.d.ts +3 -1
  109. package/dist/cjs/scheduler.js +25 -22
  110. package/dist/cjs/types.d.ts +208 -90
  111. package/dist/cjs/user/index.js +16 -7
  112. package/dist/esm/core/attempts.js +1 -1
  113. package/dist/esm/core/batch.js +2 -2
  114. package/dist/esm/core/consent.d.ts +18 -4
  115. package/dist/esm/core/consent.js +32 -17
  116. package/dist/esm/core/constants.d.ts +57 -27
  117. package/dist/esm/core/constants.js +51 -33
  118. package/dist/esm/core/db.d.ts +12 -4
  119. package/dist/esm/core/db.js +164 -35
  120. package/dist/esm/core/debug.js +1 -1
  121. package/dist/esm/core/env.d.ts +0 -3
  122. package/dist/esm/core/env.js +2 -9
  123. package/dist/esm/core/framework-id.d.ts +1 -1
  124. package/dist/esm/core/framework-id.js +3 -3
  125. package/dist/esm/core/guard.d.ts +9 -0
  126. package/dist/esm/core/guard.js +27 -14
  127. package/dist/esm/core/hooks.d.ts +7 -4
  128. package/dist/esm/core/hooks.js +3 -3
  129. package/dist/esm/core/locks.d.ts +9 -0
  130. package/dist/esm/core/locks.js +20 -0
  131. package/dist/esm/core/logger.d.ts +3 -4
  132. package/dist/esm/core/logger.js +4 -40
  133. package/dist/esm/core/state.d.ts +9 -6
  134. package/dist/esm/core/state.js +3 -5
  135. package/dist/esm/core/storage.d.ts +20 -5
  136. package/dist/esm/core/storage.js +113 -21
  137. package/dist/esm/core/stylesheet.d.ts +8 -0
  138. package/dist/esm/core/stylesheet.js +27 -0
  139. package/dist/esm/core/transport.d.ts +2 -0
  140. package/dist/esm/core/transport.js +30 -19
  141. package/dist/esm/core/utils.js +1 -1
  142. package/dist/esm/core/validate.js +2 -2
  143. package/dist/esm/device/appversion.d.ts +10 -6
  144. package/dist/esm/device/appversion.js +37 -4
  145. package/dist/esm/device/index.d.ts +28 -2
  146. package/dist/esm/device/index.js +313 -49
  147. package/dist/esm/engagement/api-rules.d.ts +32 -67
  148. package/dist/esm/engagement/api-rules.js +143 -155
  149. package/dist/esm/engagement/auto-api.js +3 -3
  150. package/dist/esm/engagement/auto-screen.d.ts +2 -0
  151. package/dist/esm/engagement/auto-screen.js +67 -4
  152. package/dist/esm/engagement/defined-events.js +1 -1
  153. package/dist/esm/engagement/send.js +12 -3
  154. package/dist/esm/engagement/session.d.ts +29 -3
  155. package/dist/esm/engagement/session.js +251 -30
  156. package/dist/esm/engagement/track.d.ts +4 -4
  157. package/dist/esm/engagement/track.js +65 -37
  158. package/dist/esm/errors/send.js +2 -2
  159. package/dist/esm/errors/track.d.ts +2 -1
  160. package/dist/esm/errors/track.js +49 -7
  161. package/dist/esm/feedback/controls.d.ts +12 -0
  162. package/dist/esm/feedback/controls.js +103 -26
  163. package/dist/esm/feedback/index.d.ts +8 -7
  164. package/dist/esm/feedback/index.js +34 -13
  165. package/dist/esm/feedback/logs.d.ts +13 -11
  166. package/dist/esm/feedback/logs.js +59 -30
  167. package/dist/esm/feedback/quartz.d.ts +18 -0
  168. package/dist/esm/feedback/quartz.js +99 -0
  169. package/dist/esm/feedback/send.d.ts +5 -2
  170. package/dist/esm/feedback/send.js +31 -31
  171. package/dist/esm/feedback/styles.d.ts +10 -0
  172. package/dist/esm/feedback/styles.js +4 -0
  173. package/dist/esm/feedback/template.d.ts +1 -1
  174. package/dist/esm/feedback/template.js +20 -12
  175. package/dist/esm/feedback/ui.d.ts +21 -6
  176. package/dist/esm/feedback/ui.js +283 -71
  177. package/dist/esm/heatmap/send.d.ts +2 -0
  178. package/dist/esm/heatmap/send.js +3 -5
  179. package/dist/esm/heatmap/track.d.ts +1 -1
  180. package/dist/esm/heatmap/track.js +87 -16
  181. package/dist/esm/index.d.ts +16 -63
  182. package/dist/esm/index.js +148 -83
  183. package/dist/esm/lifecycle.d.ts +21 -3
  184. package/dist/esm/lifecycle.js +359 -98
  185. package/dist/esm/remoteconfig/country.d.ts +4 -0
  186. package/dist/esm/remoteconfig/country.js +70 -0
  187. package/dist/esm/remoteconfig/custom.d.ts +7 -7
  188. package/dist/esm/remoteconfig/custom.js +32 -52
  189. package/dist/esm/remoteconfig/evaluate.d.ts +3 -3
  190. package/dist/esm/remoteconfig/evaluate.js +57 -44
  191. package/dist/esm/remoteconfig/fetch.d.ts +16 -9
  192. package/dist/esm/remoteconfig/fetch.js +120 -39
  193. package/dist/esm/remoteconfig/index.d.ts +19 -8
  194. package/dist/esm/remoteconfig/index.js +82 -40
  195. package/dist/esm/remoteconfig/store.d.ts +15 -7
  196. package/dist/esm/remoteconfig/store.js +68 -36
  197. package/dist/esm/remoteconfig/tz-countries.d.ts +8 -0
  198. package/dist/esm/remoteconfig/tz-countries.js +11 -0
  199. package/dist/{cjs/core → esm/remotelog}/callsite.d.ts +11 -4
  200. package/dist/esm/{core → remotelog}/callsite.js +30 -8
  201. package/dist/esm/remotelog/gate.d.ts +2 -11
  202. package/dist/esm/remotelog/gate.js +10 -32
  203. package/dist/esm/remotelog/index.d.ts +4 -21
  204. package/dist/esm/remotelog/logger.d.ts +11 -17
  205. package/dist/esm/remotelog/logger.js +33 -61
  206. package/dist/esm/remotelog/send.js +13 -13
  207. package/dist/esm/remotelogger/index.d.ts +12 -0
  208. package/dist/esm/remotelogger/index.js +13 -0
  209. package/dist/esm/scheduler.d.ts +3 -1
  210. package/dist/esm/scheduler.js +26 -24
  211. package/dist/esm/types.d.ts +208 -90
  212. package/dist/esm/user/index.js +18 -8
  213. package/dist/feedback.esm.min.js +2 -2
  214. package/dist/feedback.esm.min.js.map +1 -1
  215. package/dist/remoteconfig.esm.min.js +3 -0
  216. package/dist/remoteconfig.esm.min.js.map +1 -0
  217. package/dist/remotelogger.esm.min.js +3 -0
  218. package/dist/remotelogger.esm.min.js.map +1 -0
  219. package/package.json +16 -17
  220. package/dist/chunks/batch-BU_mTpm1.min.js +0 -3
  221. package/dist/chunks/batch-BU_mTpm1.min.js.map +0 -1
  222. package/dist/chunks/logs-Bea5zUW_.min.js +0 -3
  223. package/dist/chunks/logs-Bea5zUW_.min.js.map +0 -1
  224. package/dist/cjs/auto-init.d.ts +0 -8
  225. package/dist/cjs/auto-init.js +0 -32
  226. package/dist/cjs/heatmap/index.d.ts +0 -16
  227. package/dist/cjs/heatmap/index.js +0 -22
  228. package/dist/cjs/remotelog/index.js +0 -55
  229. package/dist/esm/auto-init.d.ts +0 -8
  230. package/dist/esm/auto-init.js +0 -29
  231. package/dist/esm/heatmap/index.d.ts +0 -16
  232. package/dist/esm/heatmap/index.js +0 -17
  233. package/dist/esm/remotelog/index.js +0 -51
  234. package/dist/heatmap.esm.min.js +0 -3
  235. package/dist/heatmap.esm.min.js.map +0 -1
  236. package/dist/style.css +0 -1
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var constants = require('../core/constants.js');
@@ -8,6 +8,7 @@ var utils = require('../core/utils.js');
8
8
  var storage = require('../core/storage.js');
9
9
  var env = require('../core/env.js');
10
10
  var consent = require('../core/consent.js');
11
+ var locks = require('../core/locks.js');
11
12
 
12
13
  /** The most recently started item of `type` that is still open (endtime 0). */
13
14
  function latestOpen(type, items) {
@@ -58,16 +59,12 @@ function closeScreensOf(session, time) {
58
59
  }, Promise.resolve());
59
60
  });
60
61
  }
61
- /** `track_session: false`, Android's automaticSessionsTrackingStatus: no sessions are recorded. */
62
- function sessionsOff() {
63
- return state.getConfig('track_session') === false; // no i18n
64
- }
65
62
  /**
66
63
  * Track the session.
67
64
  * @param sessionData A set of properties belonging to the session.
68
65
  */
69
66
  function trackSession(sessionData) {
70
- if (!consent.canTrackEngagement('trackSession')) { // no i18n
67
+ if (!consent.canTrackEngagement('trackSession', constants.AP_CONSTANTS.SESSION)) { // no i18n
71
68
  return Promise.resolve();
72
69
  }
73
70
  if (sessionData && typeof sessionData !== 'object') { // no i18n
@@ -79,13 +76,16 @@ function trackSession(sessionData) {
79
76
  logger.Console.dir(sessionData);
80
77
  return written;
81
78
  }
82
- /** This tab's session when it has one, otherwise the newest open session in storage. */
79
+ /**
80
+ * This tab's session while it is open, otherwise the newest open session in storage: the one the
81
+ * site's other tabs are on, which this tab joins rather than starting a second session beside it.
82
+ */
83
83
  function currentSession() {
84
84
  var mine = tabSessionId();
85
85
  return storage.engagement_transactions.all().then(function (items) {
86
86
  if (mine) {
87
87
  var ours = items.filter(function (item) {
88
- return item.type == constants.AP_CONSTANTS.SESSION && item.id === mine;
88
+ return item.type == constants.AP_CONSTANTS.SESSION && item.id === mine && item.endtime === 0;
89
89
  })[0];
90
90
  if (ours) {
91
91
  return ours;
@@ -94,6 +94,119 @@ function currentSession() {
94
94
  return latestOpen(constants.AP_CONSTANTS.SESSION, items);
95
95
  });
96
96
  }
97
+ /**
98
+ * This page's own id, among the tabs sharing a session. New on every page load, so a reload or a
99
+ * duplicated tab counts as a tab of its own rather than as the one it came from. Made on first use,
100
+ * not when the module loads: getNewUUID reads `screen`, which a server-side render doesn't have.
101
+ */
102
+ var tabIdValue = ''; // no i18n
103
+ function tabId() {
104
+ if (tabIdValue === '') {
105
+ tabIdValue = utils.getNewUUID();
106
+ }
107
+ return tabIdValue;
108
+ }
109
+ /**
110
+ * The tabs of this site using a session. All of them share one session, which ends when the last
111
+ * of them closes (see endCurrentSession). Kept on the stored session, never sent: see
112
+ * sendEngagementData. A session stored by an older SDK has none, and counts as this tab's alone.
113
+ */
114
+ function tabsOf(session) {
115
+ return Array.isArray(session.tabs) ? session.tabs.slice() : [];
116
+ }
117
+ function withThisTab(session) {
118
+ var tabs = tabsOf(session);
119
+ if (tabs.indexOf(tabId()) === -1) {
120
+ tabs.push(tabId());
121
+ }
122
+ return tabs;
123
+ }
124
+ /* ---------------- screen views left open by tabs that are gone ----------------
125
+ * A screen view is ended by the tab that opened it: by the next screen, or as the page hides or
126
+ * closes. A tab that reloads, closes or crashes before that write lands leaves its view open, and
127
+ * nothing ended it until the whole session did, which with tabs sharing one session can be hours.
128
+ *
129
+ * So each tab holds a Web Lock, `apptics-tab-<its id>`, for as long as it is open: the browser
130
+ * lets go of it the moment the tab is gone, however it went. A tab that starts, or comes back into
131
+ * view, ends every open view whose tab no longer holds its lock, at the time that tab was last seen
132
+ * active. Without the Web Locks API, views are left as before and end with their session. */
133
+ const TAB_LOCK_PREFIX = 'apptics-tab-'; // no i18n
134
+ /** A view this young may belong to a tab whose lock is not granted yet: left alone. */
135
+ const YOUNG_VIEW_MS = 5000;
136
+ function tabLocks() {
137
+ var locks = typeof navigator !== 'undefined' ? navigator.locks : undefined; // no i18n
138
+ return locks && typeof locks.request === 'function' && typeof locks.query === 'function' ? locks : undefined; // no i18n
139
+ }
140
+ var holdingTabLock = false;
141
+ /** Takes this tab's lock, held until the page is gone. Once per page. */
142
+ function holdTabLock() {
143
+ var locks = tabLocks();
144
+ if (!locks || holdingTabLock) {
145
+ return;
146
+ }
147
+ holdingTabLock = true;
148
+ locks.request(TAB_LOCK_PREFIX + tabId(), function () {
149
+ return new Promise(function () { });
150
+ }).catch(function () {
151
+ holdingTabLock = false;
152
+ });
153
+ }
154
+ /** Ends the open screen views of tabs that are gone. Resolves right away without Web Locks. */
155
+ function closeScreensOfGoneTabs() {
156
+ var locks = tabLocks();
157
+ if (!locks) {
158
+ return Promise.resolve();
159
+ }
160
+ var mine = tabId();
161
+ return locks.query().then(function (state) {
162
+ var alive = {};
163
+ (state.held || []).concat(state.pending || []).forEach(function (lock) {
164
+ if (lock.name && lock.name.indexOf(TAB_LOCK_PREFIX) === 0) {
165
+ alive[lock.name.slice(TAB_LOCK_PREFIX.length)] = true;
166
+ }
167
+ });
168
+ var now = utils.nowMs();
169
+ return storage.engagement_transactions.all().then(function (items) {
170
+ var gone = items.filter(function (item) {
171
+ return item.type == constants.AP_CONSTANTS.SCREEN && item.endtime === 0 && typeof item.tab === 'string' // no i18n
172
+ && item.tab !== mine && !alive[item.tab] && now - item.starttime > YOUNG_VIEW_MS;
173
+ });
174
+ if (gone.length) {
175
+ logger.Console.log('closeScreensOfGoneTabs: ending ' + gone.length + ' screen view(s) left open by a tab that is gone'); // no i18n
176
+ }
177
+ return gone.reduce(function (done, item) {
178
+ // when that tab was last seen with the view open, not now: the time since is not time spent
179
+ var end = Math.max(item.starttime, Number(item.lastseen) || item.starttime);
180
+ return done.then(function () {
181
+ return storage.engagement_transactions.update(Object.assign({}, item, { endtime: end }));
182
+ });
183
+ }, Promise.resolve());
184
+ });
185
+ }).catch(function (err) {
186
+ logger.Console.log('closeScreensOfGoneTabs: ' + err); // no i18n
187
+ });
188
+ }
189
+ /** Notes on this tab's open view that the tab is still here, the end a gone tab's view is given. */
190
+ function markScreenSeen(time) {
191
+ var current = state._ZAP._current_screen;
192
+ if (!current || !current.id || current.endtime) {
193
+ return Promise.resolve();
194
+ }
195
+ return storage.engagement_transactions.all().then(function (items) {
196
+ var open = items.filter(function (item) {
197
+ return item.type == constants.AP_CONSTANTS.SCREEN && item.id === current.id && item.endtime === 0;
198
+ })[0];
199
+ return open ? storage.engagement_transactions.update(Object.assign({}, open, { lastseen: time })) : undefined;
200
+ });
201
+ }
202
+ /**
203
+ * Every change to the session runs under a lock shared by the site's tabs: each one reads the
204
+ * stored session, changes it and writes it back, and two tabs doing that at once would each write
205
+ * over the other's change.
206
+ */
207
+ function withSessionLock(run) {
208
+ return locks.withLock('session', run); // no i18n
209
+ }
97
210
  /** The id of this tab's session. sessionStorage is per tab and survives a reload. */
98
211
  const TAB_KEY = 'apptics-session'; // no i18n
99
212
  function tabSessionId() {
@@ -112,9 +225,9 @@ function rememberTabSession(id) {
112
225
  // the session still works, it just can't be recognised after a reload
113
226
  }
114
227
  }
115
- /** True until the first session on this device has been recorded. */
228
+ /** True until the first session on this device has been recorded: device_info's hadsession. */
116
229
  function isFirstEverSession() {
117
- return utils.isEmpty(storage.user_defaults.item(HAD_SESSION_KEY));
230
+ return storage.getKeyFromDeviceInfo(HAD_SESSION_KEY) !== true;
118
231
  }
119
232
  const HAD_SESSION_KEY = 'hadsession'; // no i18n
120
233
  /**
@@ -151,7 +264,7 @@ function commitPendingSession() {
151
264
  // the flag is set here rather than at the start, so a dropped session does not consume it and
152
265
  // leave the next real session reporting firstsession false
153
266
  if (session.firstsession) {
154
- storage.user_defaults.add(HAD_SESSION_KEY, true);
267
+ storage.setDeviceInfoKey(HAD_SESSION_KEY, true);
155
268
  }
156
269
  return trackSession(session);
157
270
  }
@@ -176,6 +289,7 @@ function startNewSession(time) {
176
289
  firstsession: isFirstEverSession(),
177
290
  networkstatus: env.getNetworkStatus(),
178
291
  lastactivetime: time,
292
+ tabs: [tabId()],
179
293
  };
180
294
  // ram is optional in sessionWebSDK but checked against ram_rom ('4 GB'), which an empty
181
295
  // string cannot match. navigator.deviceMemory is Chromium-only, so Firefox and Safari have
@@ -202,25 +316,126 @@ function startNewSession(time) {
202
316
  /** The un-deferred path, for a minimum of 0. */
203
317
  function commitNow(session) {
204
318
  if (session.firstsession) {
205
- storage.user_defaults.add(HAD_SESSION_KEY, true);
319
+ storage.setDeviceInfoKey(HAD_SESSION_KEY, true);
206
320
  }
207
321
  return trackSession(session);
208
322
  }
323
+ /** Whether this tab is inactive: hidden, minimised, or its window has lost focus. */
324
+ var inactive = false;
325
+ var inactivityTimer = null;
326
+ /**
327
+ * The tab went inactive. That moment becomes the session's lastactivetime, the time it ends at if
328
+ * the user does not come back within inactiveduration. If they do not, the session is ended at it
329
+ * then, and `onEnded` sends it, rather than staying open until they return or the tab closes.
330
+ * Going inactive twice (a window blur, then the tab hidden) keeps the first moment.
331
+ */
332
+ function markTabInactive(onEnded) {
333
+ var first = !inactive;
334
+ inactive = true;
335
+ if (inactivityTimer !== null) {
336
+ clearTimeout(inactivityTimer);
337
+ }
338
+ inactivityTimer = setTimeout(function () {
339
+ inactivityTimer = null;
340
+ endInactiveSession().then(function (ended) {
341
+ if (ended) {
342
+ onEnded();
343
+ }
344
+ });
345
+ }, state._ZAP.inactiveduration * 60 * 1000 + 1000);
346
+ return first ? updateLastActiveTimeOfSession() : Promise.resolve();
347
+ }
348
+ /**
349
+ * The tab is active again. The caller then settles the session (checkAndUpdateSession): back
350
+ * within inactiveduration it continues, later it has ended and a new one starts.
351
+ */
352
+ function markTabActive() {
353
+ inactive = false;
354
+ if (inactivityTimer !== null) {
355
+ clearTimeout(inactivityTimer);
356
+ inactivityTimer = null;
357
+ }
358
+ }
359
+ /** reset(): no timer left running, and the tab counts as active. */
360
+ function resetInactivity() {
361
+ markTabActive();
362
+ }
363
+ /**
364
+ * inactiveduration has passed with the tab inactive: the session ends at its lastactivetime, when
365
+ * the user left, so the time away is not counted. Resolves true when it ended one. While another
366
+ * tab of the site is still on the session, this tab only leaves it; one whose lastactivetime is
367
+ * recent is in use elsewhere and is left alone.
368
+ */
369
+ function endInactiveSession() {
370
+ if (!state._ZAP._token || env.is_apptics_disabled()) {
371
+ return Promise.resolve(false);
372
+ }
373
+ var ended = false;
374
+ return withSessionLock(function () {
375
+ return currentSession().then(function (_currentSession) {
376
+ if (!_currentSession || _currentSession.endtime !== 0) {
377
+ return;
378
+ }
379
+ var lastActive = Number(_currentSession.lastactivetime) || utils.nowMs();
380
+ if (utils.nowMs() - lastActive < state._ZAP.inactiveduration * 60 * 1000) {
381
+ return;
382
+ }
383
+ var others = tabsOf(_currentSession).filter(function (tab) { return tab !== tabId(); });
384
+ if (others.length > 0) {
385
+ var left = Object.assign({}, _currentSession, { tabs: others });
386
+ state._ZAP._current_session = left;
387
+ return storage.engagement_transactions.update(left);
388
+ }
389
+ var endAt = Math.max(lastActive, Number(_currentSession.starttime) || lastActive);
390
+ var closed = Object.assign({}, _currentSession, { endtime: endAt, tabs: [] });
391
+ state._ZAP._current_session = closed;
392
+ ended = true;
393
+ logger.Console.log('session: inactive for ' + state._ZAP.inactiveduration + ' minutes, so it ends when the user left, ' + endAt); // no i18n
394
+ return storage.engagement_transactions.update(closed).then(function () {
395
+ return closeScreensOf(closed, endAt);
396
+ });
397
+ });
398
+ }).then(function () {
399
+ return ended;
400
+ });
401
+ }
209
402
  /**
210
- * Closes this tab's session, so it can be sent: the tab is closing or the page is being replaced.
211
- * Nothing happens when the session is already closed.
403
+ * This tab is closing, or the page is being replaced. The session ends here when this is the last
404
+ * tab using it, so it can be sent; while another tab of the site is still on it, this tab only
405
+ * leaves it, and the last tab to close ends it. Nothing happens when it is already closed.
406
+ *
407
+ * A tab closed while inactive ends the session when the user left (its lastactivetime), not when
408
+ * the tab closed: the time it sat hidden or in the background is not session time.
212
409
  */
213
410
  function endCurrentSession() {
214
411
  var time = utils.nowMs();
412
+ var wasInactive = inactive;
413
+ markTabActive();
215
414
  // nothing was tracked and the minimum was never reached: this visit is not reported at all
216
415
  if (dropPendingSession()) {
217
416
  return Promise.resolve();
218
417
  }
418
+ return withSessionLock(function () {
419
+ return closeOrLeaveSession(time, wasInactive);
420
+ });
421
+ }
422
+ function closeOrLeaveSession(now, wasInactive) {
219
423
  return currentSession().then(function (_currentSession) {
220
424
  if (!_currentSession || _currentSession.endtime !== 0) {
221
425
  return;
222
426
  }
223
- var closed = Object.assign({}, _currentSession, { endtime: time, lastactivetime: time });
427
+ var lastActive = Number(_currentSession.lastactivetime) || 0;
428
+ var time = wasInactive && lastActive > 0
429
+ ? Math.max(Math.min(lastActive, now), Number(_currentSession.starttime) || 0)
430
+ : now;
431
+ var others = tabsOf(_currentSession).filter(function (tab) { return tab !== tabId(); });
432
+ if (others.length > 0) {
433
+ var left = Object.assign({}, _currentSession, { tabs: others, lastactivetime: time });
434
+ state._ZAP._current_session = left;
435
+ logger.Console.log('endCurrentSession: ' + others.length + ' other tab(s) still on this session, so it stays open'); // no i18n
436
+ return storage.engagement_transactions.update(left);
437
+ }
438
+ var closed = Object.assign({}, _currentSession, { endtime: time, lastactivetime: time, tabs: [] });
224
439
  state._ZAP._current_session = closed;
225
440
  logger.Console.log('endCurrentSession: closing the session opened at ' + closed.starttime); // no i18n
226
441
  return storage.engagement_transactions.update(closed).then(function () {
@@ -257,18 +472,21 @@ function closeAbandonedSessions() {
257
472
  }
258
473
  function checkAndUpdateSession() {
259
474
  if (!state._ZAP._token) {
260
- logger.logFailure(constants.AP_LOG_MODULE.SESSION, 'checkAndUpdateSession: You must call apptics.init() first'); // no i18n
475
+ logger.logFailure(constants.AP_LOG_MODULE.SESSION, 'checkAndUpdateSession: You must call Apptics.init() first'); // no i18n
261
476
  return Promise.resolve();
262
477
  }
263
478
  if (env.is_apptics_disabled()) {
264
479
  return Promise.resolve();
265
480
  }
266
- if (sessionsOff()) {
267
- return Promise.resolve();
268
- }
269
481
  var time = utils.nowMs();
270
- // a tab that was killed before it could close its session: close it so it gets sent
271
- return closeAbandonedSessions().then(currentSession).then(function (_currentSession) {
482
+ return withSessionLock(function () {
483
+ return settleSession(time);
484
+ });
485
+ }
486
+ function settleSession(time) {
487
+ // a tab that was killed before it could close its session: close it so it gets sent; and the
488
+ // screen views left open by tabs that are gone, so they end now rather than with the session
489
+ return closeAbandonedSessions().then(closeScreensOfGoneTabs).then(currentSession).then(function (_currentSession) {
272
490
  // a closed session belongs to a tab that has gone: this tab starts its own
273
491
  if (!_currentSession || _currentSession.endtime !== 0) {
274
492
  return startNewSession(time);
@@ -289,13 +507,14 @@ function checkAndUpdateSession() {
289
507
  });
290
508
  }
291
509
  logger.Console.log('checkAndUpdateSession: User is back before ' + state._ZAP.inactiveduration + ' minutes so updating the lastactivitytime - ' + time); // no i18n
292
- return updateLastActiveTimeOfSession();
510
+ return touchSession();
293
511
  });
294
512
  }
295
513
  function updateLastActiveTimeOfSession() {
296
- if (sessionsOff()) {
297
- return Promise.resolve();
298
- }
514
+ return withSessionLock(touchSession);
515
+ }
516
+ /** Marks the session active now, with this tab among its tabs. Callers hold the session lock. */
517
+ function touchSession() {
299
518
  var time = utils.nowMs();
300
519
  // a pending session is not in the store yet, so it is updated in place instead
301
520
  if (pendingSession) {
@@ -308,20 +527,28 @@ function updateLastActiveTimeOfSession() {
308
527
  return;
309
528
  }
310
529
  logger.Console.log('updateLastActiveTimeOfSession: Updating the lastactivitytime - ' + time); // no i18n
311
- var _newSession = Object.assign({}, _currentSession, { lastactivetime: time });
530
+ var _newSession = Object.assign({}, _currentSession, { lastactivetime: time, tabs: withThisTab(_currentSession) });
312
531
  state._ZAP._current_session = _newSession;
313
532
  return storage.engagement_transactions.update(_newSession);
533
+ }).then(function () {
534
+ return markScreenSeen(time);
314
535
  });
315
536
  }
316
537
 
317
538
  exports.checkAndUpdateSession = checkAndUpdateSession;
318
539
  exports.closeAbandonedSessions = closeAbandonedSessions;
319
540
  exports.closeScreen = closeScreen;
541
+ exports.closeScreensOfGoneTabs = closeScreensOfGoneTabs;
320
542
  exports.commitPendingSession = commitPendingSession;
321
543
  exports.currentSession = currentSession;
322
544
  exports.dropPendingSession = dropPendingSession;
323
545
  exports.endCurrentSession = endCurrentSession;
546
+ exports.holdTabLock = holdTabLock;
547
+ exports.markTabActive = markTabActive;
548
+ exports.markTabInactive = markTabInactive;
549
+ exports.resetInactivity = resetInactivity;
324
550
  exports.startNewSession = startNewSession;
551
+ exports.tabId = tabId;
325
552
  exports.trackSession = trackSession;
326
553
  exports.updateLastActiveTimeOfSession = updateLastActiveTimeOfSession;
327
554
  exports.updateScreenWithEndtime = updateScreenWithEndtime;
@@ -1,12 +1,12 @@
1
1
  import type { Dict, Properties } from '../types.js';
2
2
  import { type DefinedEvent } from './defined-events.js';
3
3
  /**
4
- * Records an event: `trackEvent(name, group?, properties?)`, or a defined event with
4
+ * Records an event: `trackEvent(name, group, properties?)`, or a defined event with
5
5
  * `trackEvent(DefinedEvents.AP_USER_LOGIN, properties?)`, which brings its own group.
6
6
  *
7
- * As on Android, an invalid name or group is not logged. A group left out is `default`, so the
8
- * one-argument form keeps working; a group given but invalid is a mistake worth being told about,
9
- * not one to file quietly under `default`.
7
+ * The group is required. An event without one, or with an invalid name or group, is not logged,
8
+ * and the console says why (debug or not): filing it under a group the app never named would hide
9
+ * the mistake.
10
10
  */
11
11
  export declare function trackEvent(eventName: string | DefinedEvent, groupName?: string | Properties, jsonObj?: Properties): void;
12
12
  /** The app's own screen view. Automatic screen tracking calls recordScreen() instead. */
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var constants = require('../core/constants.js');
@@ -16,16 +16,30 @@ var apiRules = require('./api-rules.js');
16
16
  var definedEvents = require('./defined-events.js');
17
17
  var autoScreen = require('./auto-screen.js');
18
18
 
19
+ /** Messages already printed, so a name refused in a loop says so once. */
20
+ var refusedSaid = {};
19
21
  /**
20
- * Records an event: `trackEvent(name, group?, properties?)`, or a defined event with
22
+ * A call the SDK refused because of what the app passed it (an invalid event, group or screen
23
+ * name): reported as every failure is, and said in the console too, debug or not, once per
24
+ * message. Nothing else tells an integrator why the event or screen never shows up.
25
+ */
26
+ function refused(module, message) {
27
+ logger.logFailure(module, message);
28
+ if (!refusedSaid[message]) {
29
+ refusedSaid[message] = true;
30
+ logger.warnAlways(message);
31
+ }
32
+ }
33
+ /**
34
+ * Records an event: `trackEvent(name, group, properties?)`, or a defined event with
21
35
  * `trackEvent(DefinedEvents.AP_USER_LOGIN, properties?)`, which brings its own group.
22
36
  *
23
- * As on Android, an invalid name or group is not logged. A group left out is `default`, so the
24
- * one-argument form keeps working; a group given but invalid is a mistake worth being told about,
25
- * not one to file quietly under `default`.
37
+ * The group is required. An event without one, or with an invalid name or group, is not logged,
38
+ * and the console says why (debug or not): filing it under a group the app never named would hide
39
+ * the mistake.
26
40
  */
27
41
  function trackEvent(eventName, groupName, jsonObj) {
28
- if (!consent.canTrackEngagement('trackEvent')) { // no i18n
42
+ if (!consent.canTrackEngagement('trackEvent', constants.AP_CONSTANTS.EVENT)) { // no i18n
29
43
  return;
30
44
  }
31
45
  var defined = definedEvents.asDefinedEvent(eventName);
@@ -37,14 +51,17 @@ function trackEvent(eventName, groupName, jsonObj) {
37
51
  }
38
52
  else {
39
53
  if (typeof eventName !== 'string' || !validate.validateEventOrGroup(eventName)) { // no i18n
40
- logger.logFailure(constants.AP_LOG_MODULE.EVENT, 'AppticsEvents.addEvent: Invalid eventName: ' + String(eventName)); // no i18n
54
+ refused(constants.AP_LOG_MODULE.EVENT, 'AppticsEvent.addEvent: Invalid eventName: ' + String(eventName)); // no i18n
41
55
  return;
42
56
  }
43
- if (groupName === undefined || groupName === null || groupName === '') { // no i18n
44
- groupName = constants.AP_CONFIG.default_group_name;
57
+ // the group is required: an event without one (or with its properties in the group's
58
+ // place) is not logged, and the console says why
59
+ if (groupName === undefined || groupName === null || groupName === '' || typeof groupName === 'object') { // no i18n
60
+ refused(constants.AP_LOG_MODULE.EVENT, 'AppticsEvent.addEvent: groupName is required for "' + eventName + '": addEvent(eventName, groupName, properties?)'); // no i18n
61
+ return;
45
62
  }
46
- else if (typeof groupName !== 'string' || !validate.validateEventOrGroup(groupName)) { // no i18n
47
- logger.logFailure(constants.AP_LOG_MODULE.EVENT, 'AppticsEvents.addEvent: Invalid groupName for "' + eventName + '": ' + String(groupName)); // no i18n
63
+ if (typeof groupName !== 'string' || !validate.validateEventOrGroup(groupName)) { // no i18n
64
+ refused(constants.AP_LOG_MODULE.EVENT, 'AppticsEvent.addEvent: Invalid groupName for "' + eventName + '": ' + String(groupName)); // no i18n
48
65
  return;
49
66
  }
50
67
  }
@@ -70,7 +87,7 @@ function trackEvent(eventName, groupName, jsonObj) {
70
87
  session.commitPendingSession();
71
88
  debug.noteDebugActivity();
72
89
  storage.engagement_transactions.add(eventData);
73
- logger.Console.log('AppticsEvents.addEvent(\'' + eventName + '\',\'' + groupName + '\',' + JSON.stringify(_jsonObj || {}) + ')'); // no i18n
90
+ logger.Console.log('AppticsEvent.addEvent(\'' + eventName + '\',' + '\'' + groupName + '\'' + ',' + JSON.stringify(_jsonObj || {}) + ')'); // no i18n
74
91
  logger.Console.dir(eventData);
75
92
  }
76
93
  /**
@@ -80,7 +97,7 @@ function trackEvent(eventName, groupName, jsonObj) {
80
97
  */
81
98
  function inScreenAt(screenName, jsonObj, id, startedAt) {
82
99
  if (!validate.validateScreenName(screenName)) {
83
- logger.logFailure(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreenTracker.inScreen: Invalid screenName: ' + String(screenName)); // no i18n
100
+ refused(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreen.inScreen: Invalid screenName: ' + String(screenName)); // no i18n
84
101
  return;
85
102
  }
86
103
  // the app named this screen itself: the automatic view of the same navigation gives way to it
@@ -90,7 +107,7 @@ function inScreenAt(screenName, jsonObj, id, startedAt) {
90
107
  /** Ends the screen view inScreen() began, as Android's AppticsScreenTracker.outScreen(id). */
91
108
  function outScreenAt(id, endedAt) {
92
109
  if (utils.isEmpty(id)) {
93
- logger.logFailure(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreenTracker.outScreen: no screen id given'); // no i18n
110
+ logger.logFailure(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreen.outScreen: no screen id given'); // no i18n
94
111
  return;
95
112
  }
96
113
  session.closeScreen(id, endedAt);
@@ -103,11 +120,11 @@ function outScreenAt(id, endedAt) {
103
120
  * An open view is not sent until it is closed, as an open session is not.
104
121
  */
105
122
  function recordScreen(screenName, jsonObj, id, startedAt, implicit) {
106
- if (!consent.canTrackEngagement('inScreen')) { // no i18n
123
+ if (!consent.canTrackEngagement('inScreen', constants.AP_CONSTANTS.SCREEN)) { // no i18n
107
124
  return;
108
125
  }
109
126
  if (!validate.validateScreenName(screenName)) {
110
- logger.logFailure(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreenTracker.inScreen: Invalid screenName: ' + String(screenName)); // no i18n
127
+ refused(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreen.inScreen: Invalid screenName: ' + String(screenName)); // no i18n
111
128
  return;
112
129
  }
113
130
  jsonObj = jsonObj || {};
@@ -124,7 +141,10 @@ function recordScreen(screenName, jsonObj, id, startedAt, implicit) {
124
141
  networkstatus: env.getNetworkStatus(),
125
142
  orientation: env.getOrientation(),
126
143
  sessionstarttime: state._ZAP._current_session.starttime || time,
127
- customproperties: _jsonObj
144
+ customproperties: _jsonObj,
145
+ // the tab showing it, so a tab that is gone can have its view ended (closeScreensOfGoneTabs).
146
+ // SDK bookkeeping, removed before sending, as lastseen is
147
+ tab: session.tabId(),
128
148
  };
129
149
  // the screen being left ends where this one starts
130
150
  var previous = state._ZAP._current_screen && state._ZAP._current_screen.id;
@@ -137,7 +157,7 @@ function recordScreen(screenName, jsonObj, id, startedAt, implicit) {
137
157
  // `implicit`: a view recorded only so a heatmap record has one to belong to. Kept on the
138
158
  // in-memory copy alone, never on the stored item, which goes to the server as it is
139
159
  state._ZAP._current_screen = implicit ? Object.assign({}, screenData, { implicit: true }) : screenData;
140
- logger.Console.log('AppticsScreenTracker.inScreen(\'' + screenName + '\',' + JSON.stringify(_jsonObj || {}) + ')'); // no i18n
160
+ logger.Console.log('AppticsScreen.inScreen(\'' + screenName + '\',' + JSON.stringify(_jsonObj || {}) + ')'); // no i18n
141
161
  logger.Console.dir(screenData);
142
162
  }
143
163
  /**
@@ -196,7 +216,7 @@ function withoutQueryForLog(path) {
196
216
  return String(path || '').split(/[?#]/)[0]; // no i18n
197
217
  }
198
218
  function trackApi(jsonObj) {
199
- if (!consent.canTrackEngagement('trackApi')) { // no i18n
219
+ if (!consent.canTrackEngagement('trackApi', constants.AP_CONSTANTS.API)) { // no i18n
200
220
  return;
201
221
  }
202
222
  jsonObj = jsonObj || {};
@@ -226,16 +246,19 @@ function trackApi(jsonObj) {
226
246
  var hostname = jsonObj.hostname || '';
227
247
  var port = (typeof jsonObj.port === 'number') ? jsonObj.port : 0;
228
248
  var path = jsonObj.path || '';
249
+ // a call reported by its parts, a hostname and a path with no url: its scheme and port are its
250
+ // own (https and 443 unless given), not the page's, which belong to another host
251
+ var partsOnly = utils.isEmpty(jsonObj.url) && !utils.isEmpty(jsonObj.hostname);
229
252
  if (!utils.isEmpty(rawUrl)) {
230
253
  try {
231
254
  var urlObj = new URL(rawUrl, window.location.origin);
232
- if (utils.isEmpty(scheme)) {
255
+ if (utils.isEmpty(scheme) && !partsOnly) {
233
256
  scheme = urlObj.protocol.replace(':', ''); // "https:"
234
257
  }
235
258
  if (utils.isEmpty(hostname)) {
236
259
  hostname = urlObj.hostname;
237
260
  }
238
- if (!port) {
261
+ if (!port && !partsOnly) {
239
262
  if (urlObj.port) {
240
263
  port = parseInt(urlObj.port, 10);
241
264
  }
@@ -256,22 +279,27 @@ function trackApi(jsonObj) {
256
279
  }
257
280
  // only http and https exist as far as the proxy's api_scheme is concerned
258
281
  scheme = (scheme === 'https' || scheme === 'http') ? scheme : 'https'; // no i18n
282
+ if (!port) {
283
+ port = scheme === 'https' ? 443 : 80; // no i18n
284
+ }
259
285
  // a hostname the proxy refuses cannot be repaired without inventing one, so the call is
260
286
  // dropped here and said out loud. localhost and bare IPs land here: api_hostname wants at
261
287
  // least one dot and an alphabetic suffix, which is worth knowing when nothing shows up locally
262
288
  if (!API_HOSTNAME.test(hostname)) {
263
- logger.logFailure(constants.AP_LOG_MODULE.API, 'AppticsApiTracker: hostname not accepted by the server: ' + String(hostname)); // no i18n
289
+ logger.logFailure(constants.AP_LOG_MODULE.API, 'AppticsApi: hostname not accepted by the server: ' + String(hostname)); // no i18n
264
290
  return;
265
291
  }
266
- // configureApiTracking: the app's rules decide whether this call is recorded at all
267
- if (!apiRules.hostAllowed(hostname) || apiRules.endpointIgnored(path)) {
268
- logger.Console.log('AppticsApiTracker: ' + hostname + withoutQueryForLog(path) + ' is left out by configureApiTracking'); // no i18n
292
+ // configureApiTracking: the app's rules decide whether this call is recorded at all, tried on
293
+ // the URL as it was called, without its query
294
+ var defaultPort = (scheme === 'https' && port === 443) || (scheme === 'http' && port === 80); // no i18n
295
+ var calledUrl = scheme + '://' + hostname + (port && !defaultPort ? ':' + port : '') + (String(path).charAt(0) === '/' ? '' : '/') + path; // no i18n
296
+ if (!apiRules.urlTracked(calledUrl)) {
297
+ logger.Console.log('AppticsApi: ' + hostname + withoutQueryForLog(path) + ' is left out by configureApiTracking'); // no i18n
269
298
  return;
270
299
  }
271
- // and the name it is recorded under: ids become *, regional hosts one group, so the console
272
- // groups calls by endpoint rather than by every id that went through it
300
+ // and the name it is recorded under: ids become *, so the console groups calls by endpoint
301
+ // rather than by every id that went through it
273
302
  path = sanitizeApiPath(apiRules.normalizeApiPath(path));
274
- hostname = apiRules.groupedHost(hostname);
275
303
  var sessionStart = state._ZAP._current_session.starttime || starttime;
276
304
  // no customproperties: apiWebSDK does not declare the key, unlike the screen and event
277
305
  // templates, so anything extra the caller passes is context for the log line only
@@ -296,7 +324,7 @@ function trackApi(jsonObj) {
296
324
  session.commitPendingSession();
297
325
  debug.noteDebugActivity();
298
326
  storage.engagement_transactions.add(apiData);
299
- logger.Console.log('AppticsApiTracker(\'' + method + ' ' + scheme + '://' + hostname + path + '\')'); // no i18n
327
+ logger.Console.log('AppticsApi(\'' + method + ' ' + scheme + '://' + hostname + path + '\')'); // no i18n
300
328
  logger.Console.dir(apiData);
301
329
  }
302
330
  /** Begun calls by id. Bounded, so an app that starts calls it never ends can't grow it forever. */
@@ -324,7 +352,7 @@ function startTrackApi(url, method) {
324
352
  function endTrackApiAt(id, responseCode, responseMessage, endedAt) {
325
353
  var open = openCalls[id];
326
354
  if (!open) {
327
- logger.logFailure(constants.AP_LOG_MODULE.API, 'AppticsApiTracker.endTrackApi: no call started with id ' + String(id)); // no i18n
355
+ logger.logFailure(constants.AP_LOG_MODULE.API, 'AppticsApi.endTrackApi: no call started with id ' + String(id)); // no i18n
328
356
  return;
329
357
  }
330
358
  delete openCalls[id];
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var state = require('../core/state.js');
@@ -14,7 +14,7 @@ var transport = require('../core/transport.js');
14
14
  * Sends pending errors to the Apptics API.
15
15
  */
16
16
  function sendErrorData(forget) {
17
- // errortracking off (getupdates): queued errors stay until tracking is back on or they expire
17
+ // js_error off (getsdkconfig): queued errors stay until tracking is back on or they expire
18
18
  if (env.is_apptics_disabled() || !consent.shouldTrackOrSendData() || !state._ZAP._errorTracking) {
19
19
  return Promise.resolve();
20
20
  }
@@ -1,4 +1,5 @@
1
1
  import type { Properties } from '../types.js';
2
2
  export declare function trackError(errorEvent: any, jsonObj?: Properties): void;
3
- export declare function enableGlobalErrorHandler(status?: boolean): void;
3
+ /** AppticsError.setErrorTracking: uncaught errors on or off, as the `track_error` config sets it. */
4
+ export declare function setErrorTracking(status?: boolean): void;
4
5
  export declare function extractMethodNameFromStackTrace(stackTrace: string): string;