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

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 (226) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +13 -0
  3. package/README.md +747 -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/batch-BU_mTpm1.min.js +3 -0
  9. package/dist/chunks/batch-BU_mTpm1.min.js.map +1 -0
  10. package/dist/chunks/logs-Bea5zUW_.min.js +3 -0
  11. package/dist/chunks/logs-Bea5zUW_.min.js.map +1 -0
  12. package/dist/cjs/auto-init.d.ts +8 -0
  13. package/dist/cjs/auto-init.js +32 -0
  14. package/dist/cjs/core/attempts.d.ts +28 -0
  15. package/dist/cjs/core/attempts.js +113 -0
  16. package/dist/cjs/core/batch.d.ts +32 -0
  17. package/dist/cjs/core/batch.js +115 -0
  18. package/dist/cjs/core/callsite.d.ts +28 -0
  19. package/dist/cjs/core/callsite.js +93 -0
  20. package/dist/cjs/core/consent.d.ts +23 -0
  21. package/dist/cjs/core/consent.js +130 -0
  22. package/dist/cjs/core/constants.d.ts +212 -0
  23. package/dist/cjs/core/constants.js +299 -0
  24. package/dist/cjs/core/db.d.ts +40 -0
  25. package/dist/cjs/core/db.js +334 -0
  26. package/dist/cjs/core/debug.d.ts +22 -0
  27. package/dist/cjs/core/debug.js +88 -0
  28. package/dist/cjs/core/env.d.ts +28 -0
  29. package/dist/cjs/core/env.js +267 -0
  30. package/dist/cjs/core/framework-id.d.ts +1 -0
  31. package/dist/cjs/core/framework-id.js +9 -0
  32. package/dist/cjs/core/guard.d.ts +2 -0
  33. package/dist/cjs/core/guard.js +72 -0
  34. package/dist/cjs/core/hooks.d.ts +41 -0
  35. package/dist/cjs/core/hooks.js +23 -0
  36. package/dist/cjs/core/logger.d.ts +16 -0
  37. package/dist/cjs/core/logger.js +86 -0
  38. package/dist/cjs/core/state.d.ts +69 -0
  39. package/dist/cjs/core/state.js +78 -0
  40. package/dist/cjs/core/storage.d.ts +46 -0
  41. package/dist/cjs/core/storage.js +229 -0
  42. package/dist/cjs/core/transport.d.ts +83 -0
  43. package/dist/cjs/core/transport.js +441 -0
  44. package/dist/cjs/core/utils.d.ts +26 -0
  45. package/dist/cjs/core/utils.js +175 -0
  46. package/dist/cjs/core/validate.d.ts +18 -0
  47. package/dist/cjs/core/validate.js +233 -0
  48. package/dist/cjs/device/appversion.d.ts +20 -0
  49. package/dist/cjs/device/appversion.js +158 -0
  50. package/dist/cjs/device/index.d.ts +23 -0
  51. package/dist/cjs/device/index.js +372 -0
  52. package/dist/cjs/engagement/api-rules.d.ts +84 -0
  53. package/dist/cjs/engagement/api-rules.js +219 -0
  54. package/dist/cjs/engagement/auto-api.d.ts +7 -0
  55. package/dist/cjs/engagement/auto-api.js +200 -0
  56. package/dist/cjs/engagement/auto-screen.d.ts +16 -0
  57. package/dist/cjs/engagement/auto-screen.js +241 -0
  58. package/dist/cjs/engagement/defined-events.d.ts +23 -0
  59. package/dist/cjs/engagement/defined-events.js +58 -0
  60. package/dist/cjs/engagement/send.d.ts +6 -0
  61. package/dist/cjs/engagement/send.js +99 -0
  62. package/dist/cjs/engagement/session.d.ts +42 -0
  63. package/dist/cjs/engagement/session.js +327 -0
  64. package/dist/cjs/engagement/track.d.ts +56 -0
  65. package/dist/cjs/engagement/track.js +350 -0
  66. package/dist/cjs/errors/send.d.ts +6 -0
  67. package/dist/cjs/errors/send.js +73 -0
  68. package/dist/cjs/errors/track.d.ts +4 -0
  69. package/dist/cjs/errors/track.js +127 -0
  70. package/dist/cjs/feedback/controls.d.ts +31 -0
  71. package/dist/cjs/feedback/controls.js +286 -0
  72. package/dist/cjs/feedback/index.d.ts +8 -0
  73. package/dist/cjs/feedback/index.js +37 -0
  74. package/dist/cjs/feedback/logs.d.ts +40 -0
  75. package/dist/cjs/feedback/logs.js +202 -0
  76. package/dist/cjs/feedback/send.d.ts +25 -0
  77. package/dist/cjs/feedback/send.js +178 -0
  78. package/dist/cjs/feedback/template.d.ts +2 -0
  79. package/dist/cjs/feedback/template.js +162 -0
  80. package/dist/cjs/feedback/ui.d.ts +55 -0
  81. package/dist/cjs/feedback/ui.js +631 -0
  82. package/dist/cjs/heatmap/index.d.ts +16 -0
  83. package/dist/cjs/heatmap/index.js +22 -0
  84. package/dist/cjs/heatmap/send.d.ts +13 -0
  85. package/dist/cjs/heatmap/send.js +82 -0
  86. package/dist/cjs/heatmap/track.d.ts +4 -0
  87. package/dist/cjs/heatmap/track.js +377 -0
  88. package/dist/cjs/index.d.ts +68 -0
  89. package/dist/cjs/index.js +150 -0
  90. package/dist/cjs/lifecycle.d.ts +14 -0
  91. package/dist/cjs/lifecycle.js +538 -0
  92. package/dist/cjs/package.json +3 -0
  93. package/dist/cjs/remoteconfig/custom.d.ts +10 -0
  94. package/dist/cjs/remoteconfig/custom.js +78 -0
  95. package/dist/cjs/remoteconfig/evaluate.d.ts +24 -0
  96. package/dist/cjs/remoteconfig/evaluate.js +171 -0
  97. package/dist/cjs/remoteconfig/fetch.d.ts +24 -0
  98. package/dist/cjs/remoteconfig/fetch.js +214 -0
  99. package/dist/cjs/remoteconfig/index.d.ts +13 -0
  100. package/dist/cjs/remoteconfig/index.js +90 -0
  101. package/dist/cjs/remoteconfig/store.d.ts +18 -0
  102. package/dist/cjs/remoteconfig/store.js +98 -0
  103. package/dist/cjs/remotelog/gate.d.ts +11 -0
  104. package/dist/cjs/remotelog/gate.js +54 -0
  105. package/dist/cjs/remotelog/index.d.ts +25 -0
  106. package/dist/cjs/remotelog/index.js +55 -0
  107. package/dist/cjs/remotelog/logger.d.ts +28 -0
  108. package/dist/cjs/remotelog/logger.js +139 -0
  109. package/dist/cjs/remotelog/send.d.ts +13 -0
  110. package/dist/cjs/remotelog/send.js +153 -0
  111. package/dist/cjs/scheduler.d.ts +8 -0
  112. package/dist/cjs/scheduler.js +78 -0
  113. package/dist/cjs/types.d.ts +312 -0
  114. package/dist/cjs/user/index.d.ts +33 -0
  115. package/dist/cjs/user/index.js +178 -0
  116. package/dist/esm/auto-init.d.ts +8 -0
  117. package/dist/esm/auto-init.js +29 -0
  118. package/dist/esm/core/attempts.d.ts +28 -0
  119. package/dist/esm/core/attempts.js +106 -0
  120. package/dist/esm/core/batch.d.ts +32 -0
  121. package/dist/esm/core/batch.js +108 -0
  122. package/dist/esm/core/callsite.d.ts +28 -0
  123. package/dist/esm/core/callsite.js +89 -0
  124. package/dist/esm/core/consent.d.ts +23 -0
  125. package/dist/esm/core/consent.js +120 -0
  126. package/dist/esm/core/constants.d.ts +212 -0
  127. package/dist/esm/core/constants.js +277 -0
  128. package/dist/esm/core/db.d.ts +40 -0
  129. package/dist/esm/core/db.js +324 -0
  130. package/dist/esm/core/debug.d.ts +22 -0
  131. package/dist/esm/core/debug.js +81 -0
  132. package/dist/esm/core/env.d.ts +28 -0
  133. package/dist/esm/core/env.js +251 -0
  134. package/dist/esm/core/framework-id.d.ts +1 -0
  135. package/dist/esm/core/framework-id.js +7 -0
  136. package/dist/esm/core/guard.d.ts +2 -0
  137. package/dist/esm/core/guard.js +70 -0
  138. package/dist/esm/core/hooks.d.ts +41 -0
  139. package/dist/esm/core/hooks.js +21 -0
  140. package/dist/esm/core/logger.d.ts +16 -0
  141. package/dist/esm/core/logger.js +82 -0
  142. package/dist/esm/core/state.d.ts +69 -0
  143. package/dist/esm/core/state.js +73 -0
  144. package/dist/esm/core/storage.d.ts +46 -0
  145. package/dist/esm/core/storage.js +219 -0
  146. package/dist/esm/core/transport.d.ts +83 -0
  147. package/dist/esm/core/transport.js +425 -0
  148. package/dist/esm/core/utils.d.ts +26 -0
  149. package/dist/esm/core/utils.js +161 -0
  150. package/dist/esm/core/validate.d.ts +18 -0
  151. package/dist/esm/core/validate.js +226 -0
  152. package/dist/esm/device/appversion.d.ts +20 -0
  153. package/dist/esm/device/appversion.js +153 -0
  154. package/dist/esm/device/index.d.ts +23 -0
  155. package/dist/esm/device/index.js +362 -0
  156. package/dist/esm/engagement/api-rules.d.ts +84 -0
  157. package/dist/esm/engagement/api-rules.js +211 -0
  158. package/dist/esm/engagement/auto-api.d.ts +7 -0
  159. package/dist/esm/engagement/auto-api.js +198 -0
  160. package/dist/esm/engagement/auto-screen.d.ts +16 -0
  161. package/dist/esm/engagement/auto-screen.js +238 -0
  162. package/dist/esm/engagement/defined-events.d.ts +23 -0
  163. package/dist/esm/engagement/defined-events.js +55 -0
  164. package/dist/esm/engagement/send.d.ts +6 -0
  165. package/dist/esm/engagement/send.js +96 -0
  166. package/dist/esm/engagement/session.d.ts +42 -0
  167. package/dist/esm/engagement/session.js +315 -0
  168. package/dist/esm/engagement/track.d.ts +56 -0
  169. package/dist/esm/engagement/track.js +340 -0
  170. package/dist/esm/errors/send.d.ts +6 -0
  171. package/dist/esm/errors/send.js +70 -0
  172. package/dist/esm/errors/track.d.ts +4 -0
  173. package/dist/esm/errors/track.js +123 -0
  174. package/dist/esm/feedback/controls.d.ts +31 -0
  175. package/dist/esm/feedback/controls.js +280 -0
  176. package/dist/esm/feedback/index.d.ts +8 -0
  177. package/dist/esm/feedback/index.js +30 -0
  178. package/dist/esm/feedback/logs.d.ts +40 -0
  179. package/dist/esm/feedback/logs.js +188 -0
  180. package/dist/esm/feedback/send.d.ts +25 -0
  181. package/dist/esm/feedback/send.js +175 -0
  182. package/dist/esm/feedback/template.d.ts +2 -0
  183. package/dist/esm/feedback/template.js +159 -0
  184. package/dist/esm/feedback/ui.d.ts +55 -0
  185. package/dist/esm/feedback/ui.js +626 -0
  186. package/dist/esm/heatmap/index.d.ts +16 -0
  187. package/dist/esm/heatmap/index.js +17 -0
  188. package/dist/esm/heatmap/send.d.ts +13 -0
  189. package/dist/esm/heatmap/send.js +79 -0
  190. package/dist/esm/heatmap/track.d.ts +4 -0
  191. package/dist/esm/heatmap/track.js +374 -0
  192. package/dist/esm/index.d.ts +68 -0
  193. package/dist/esm/index.js +122 -0
  194. package/dist/esm/lifecycle.d.ts +14 -0
  195. package/dist/esm/lifecycle.js +534 -0
  196. package/dist/esm/package.json +3 -0
  197. package/dist/esm/remoteconfig/custom.d.ts +10 -0
  198. package/dist/esm/remoteconfig/custom.js +74 -0
  199. package/dist/esm/remoteconfig/evaluate.d.ts +24 -0
  200. package/dist/esm/remoteconfig/evaluate.js +166 -0
  201. package/dist/esm/remoteconfig/fetch.d.ts +24 -0
  202. package/dist/esm/remoteconfig/fetch.js +210 -0
  203. package/dist/esm/remoteconfig/index.d.ts +13 -0
  204. package/dist/esm/remoteconfig/index.js +85 -0
  205. package/dist/esm/remoteconfig/store.d.ts +18 -0
  206. package/dist/esm/remoteconfig/store.js +91 -0
  207. package/dist/esm/remotelog/gate.d.ts +11 -0
  208. package/dist/esm/remotelog/gate.js +48 -0
  209. package/dist/esm/remotelog/index.d.ts +25 -0
  210. package/dist/esm/remotelog/index.js +51 -0
  211. package/dist/esm/remotelog/logger.d.ts +28 -0
  212. package/dist/esm/remotelog/logger.js +136 -0
  213. package/dist/esm/remotelog/send.d.ts +13 -0
  214. package/dist/esm/remotelog/send.js +149 -0
  215. package/dist/esm/scheduler.d.ts +8 -0
  216. package/dist/esm/scheduler.js +74 -0
  217. package/dist/esm/types.d.ts +312 -0
  218. package/dist/esm/user/index.d.ts +33 -0
  219. package/dist/esm/user/index.js +170 -0
  220. package/dist/feedback.esm.min.js +3 -0
  221. package/dist/feedback.esm.min.js.map +1 -0
  222. package/dist/heatmap.esm.min.js +3 -0
  223. package/dist/heatmap.esm.min.js.map +1 -0
  224. package/dist/style.css +1 -0
  225. package/package.json +124 -7
  226. package/src/appticssdk.js +0 -1
@@ -0,0 +1,534 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { REQUIRED_CONFIG, AP_CONFIG, CONFIG_ALIASES, DEFAULT_INACTIVE_MINUTES } from './core/constants.js';
3
+ import { _ZAP } from './core/state.js';
4
+ import { warnAlways, Console } from './core/logger.js';
5
+ import { isEmpty, getNewUUID, isSuccess } from './core/utils.js';
6
+ import { storageReady, user_defaults, tracking_preference, engagement_transactions, error_transactions } 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 { getTrackingStatus } from './core/consent.js';
11
+ import { restoreServerSettings, checkAndUpdateDeviceInfo, refreshServerSettings, updateDeviceWithApptics, needsDevice, deviceReady } from './device/index.js';
12
+ import { registerAppVersion, clearAppVersion } from './device/appversion.js';
13
+ import { checkAndUpdateSession, updateLastActiveTimeOfSession, updateScreenWithEndtime, endCurrentSession } from './engagement/session.js';
14
+ import { enableApiTracking } from './engagement/auto-api.js';
15
+ import { enableScreenTracking } from './engagement/auto-screen.js';
16
+ import { resumeScreen, trackEvent } from './engagement/track.js';
17
+ import { trackError } from './errors/track.js';
18
+ import { startTimers, flush, stopTimers } from './scheduler.js';
19
+ import './remotelog/index.js';
20
+ import { getUserInfo } from './user/index.js';
21
+ import { clearAttempts } from './core/attempts.js';
22
+ import { sendStoredLogs, forgetStoredLogs } from './remotelog/send.js';
23
+
24
+ let listenersAttached = false;
25
+ /** The config init() was last called with; reset() starts again from it. */
26
+ let lastConfig = null;
27
+ /** Bumped by every init(); a start() from an earlier init() that was reset in between does nothing. */
28
+ let generation = 0;
29
+ function isBrowser() {
30
+ if (typeof window === 'undefined' || typeof document === 'undefined' || typeof Promise === 'undefined') { // no i18n
31
+ return false;
32
+ }
33
+ try {
34
+ return typeof indexedDB !== 'undefined' || !!window.localStorage; // no i18n
35
+ }
36
+ catch (err) {
37
+ return false; // storage access can throw in sandboxed frames
38
+ }
39
+ }
40
+ /**
41
+ * Canonical config: serviceUrl, zak, identifier, appversion.
42
+ * The console snippet uses older names (base_domain, token), which are accepted here.
43
+ * serviceUrl 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_ALIASES).forEach(function (key) {
48
+ if (isEmpty(settings[key]) && !isEmpty(settings[CONFIG_ALIASES[key]])) {
49
+ settings[key] = settings[CONFIG_ALIASES[key]];
50
+ }
51
+ });
52
+ if (!isEmpty(settings.serviceUrl)) {
53
+ settings.serviceUrl = String(settings.serviceUrl).replace(/\/+$/, ''); // no i18n
54
+ }
55
+ settings.appversion = appVersionText(settings.appversion);
56
+ return settings;
57
+ }
58
+ /**
59
+ * The version as the text it is stored and sent as: a string trimmed, a finite number as its digits.
60
+ * Anything else — blank, NaN, an object — is '', which init() reports as missing.
61
+ */
62
+ function appVersionText(value) {
63
+ if (typeof value === 'number') { // no i18n
64
+ return isFinite(value) ? String(value) : ''; // no i18n
65
+ }
66
+ return typeof value === 'string' ? value.trim() : ''; // no i18n
67
+ }
68
+ /**
69
+ * The placeholders the console's snippets and the docs show for appversion. Starting with one
70
+ * would register a version that was never shipped, and every visit after it would report under it.
71
+ */
72
+ const APPVERSION_PLACEHOLDERS = ['YOUR_APP_VERSION', 'YOUR_BUILD_OR_APP_VERSION', 'YOUR_APPVERSION']; // no i18n
73
+ function isAppVersionPlaceholder(version) {
74
+ return APPVERSION_PLACEHOLDERS.indexOf(version.toUpperCase()) !== -1;
75
+ }
76
+ /** Which app this browser's stored data belongs to, before app/addversion has named it. */
77
+ function appKey(settings) {
78
+ return settings.serviceUrl + '|' + settings.identifier; // no i18n
79
+ }
80
+ /**
81
+ * Data stored for another app on this origin is discarded before anything else reads it,
82
+ * including the stored app/addversion answer that would otherwise hand out that app's ids.
83
+ */
84
+ function discardOtherAppData(settings) {
85
+ var stored = user_defaults.item('appkey'); // no i18n
86
+ if (!isEmpty(stored) && stored !== appKey(settings)) {
87
+ Console.log('init: stored data belongs to another app, resetting'); // no i18n
88
+ clearStorage();
89
+ }
90
+ user_defaults.add('appkey', appKey(settings)); // no i18n
91
+ }
92
+ /**
93
+ * Timing an app may tune in init(). Each has a range: a value outside it is ignored with a
94
+ * warning rather than applied, since a 10 ms flush interval would hammer the server.
95
+ */
96
+ const TUNABLE = Object.freeze([
97
+ { key: 'batch_flush_interval', min: 1000, max: 3600000 }, // no i18n
98
+ { key: 'getupdates_interval', min: 10000, max: 86400000 }, // no i18n
99
+ { key: 'batch_size', min: 1, max: 500 }, // no i18n
100
+ { key: 'batch_request_timeout', min: 1, max: 30 }, // no i18n
101
+ { key: 'min_session_duration', min: 0, max: 60000 }, // no i18n
102
+ { key: 'heatmap_max_per_session', min: 0, max: 10000 }, // no i18n
103
+ ]);
104
+ /** Reads the tunable timings out of the config. Anything missing goes back to its default. */
105
+ function applyIntervals(config) {
106
+ TUNABLE.forEach(function (rule) {
107
+ var value = config[rule.key];
108
+ // every init() decides these on its own, so a value from an earlier one never lingers
109
+ _ZAP._config[rule.key] = AP_CONFIG[rule.key];
110
+ if (isEmpty(value)) {
111
+ return;
112
+ }
113
+ var num = Number(value);
114
+ if (!isFinite(num) || num < rule.min || num > rule.max) {
115
+ warnAlways('Apptics.init: ' + rule.key + ' must be between ' + rule.min + ' and ' + rule.max + ', keeping ' + _ZAP._config[rule.key]); // no i18n
116
+ return;
117
+ }
118
+ _ZAP._config[rule.key] = num;
119
+ Console.log('Apptics.init: ' + rule.key + ' set to ' + num); // no i18n
120
+ });
121
+ // inactiveduration lives on state, not in _config
122
+ _ZAP.inactiveduration = DEFAULT_INACTIVE_MINUTES;
123
+ if (!isEmpty(config.inactiveduration)) {
124
+ var minutes = Number(config.inactiveduration);
125
+ if (!isFinite(minutes) || minutes < 1 || minutes > 1440) {
126
+ warnAlways('Apptics.init: inactiveduration must be between 1 and 1440 minutes, keeping ' + _ZAP.inactiveduration); // no i18n
127
+ }
128
+ else {
129
+ _ZAP.inactiveduration = minutes;
130
+ Console.log('Apptics.init: inactiveduration set to ' + minutes); // no i18n
131
+ }
132
+ }
133
+ }
134
+ function clearStorage() {
135
+ clearAttempts();
136
+ user_defaults.clear();
137
+ engagement_transactions.clear();
138
+ error_transactions.clear();
139
+ }
140
+ /**
141
+ * Starts the SDK. The config object is required: pass it directly, or let the console snippet
142
+ * supply it (auto-init reads window.appticssettings._defaultoptions and calls init with it).
143
+ * Returns true when the config has serviceUrl, zak, identifier and appversion and start-up has
144
+ * begun (see ready()), false when it was already running, the config is missing or incomplete, or
145
+ * there is no browser. Start-up calls app/addversion with those four, which answers with aaid, the
146
+ * portal and project ids and the rest; then device/add registers the browser, as in 1.x.
147
+ */
148
+ function init(config) {
149
+ if (!config || typeof config !== 'object') { // no i18n
150
+ warnAlways('Apptics.init: a config object is required, e.g. apptics.init({ serviceUrl, zak, identifier, appversion })'); // no i18n
151
+ return false;
152
+ }
153
+ if (_ZAP._initialised) {
154
+ Console.warn('Apptics.init: already initialised; call apptics.reset() to start again'); // no i18n
155
+ return false;
156
+ }
157
+ if (!isBrowser()) {
158
+ warnAlways('Apptics.init: skipped, no browser with storage and Promise support'); // no i18n
159
+ return false;
160
+ }
161
+ var settings = normaliseConfig(config);
162
+ var missing = REQUIRED_CONFIG.filter(function (key) {
163
+ return isEmpty(settings[key]);
164
+ });
165
+ if (missing.length > 0) {
166
+ warnAlways('Apptics.init: missing required config: ' + missing.join(', ')); // no i18n
167
+ return false;
168
+ }
169
+ if (isAppVersionPlaceholder(settings.appversion)) {
170
+ warnAlways('Apptics.init: appversion is still the placeholder "' + settings.appversion // no i18n
171
+ + '"; replace it with your app\'s version or build number, e.g. \'2.4.0\''); // no i18n
172
+ return false;
173
+ }
174
+ _ZAP._defaultoptions = settings;
175
+ // every request goes to serviceUrl; there is no other host to learn about
176
+ _ZAP._defaultoptions.base_domain = settings.serviceUrl;
177
+ // marks the SDK as started for the checks that need it; app/addversion replaces it with aaid
178
+ _ZAP._token = settings.identifier;
179
+ // console_log: the SDK's own activity in the browser console
180
+ if (!isEmpty(config.console_log)) {
181
+ _ZAP._config.debug = !!config.console_log;
182
+ }
183
+ // track_session: false records no sessions, as Android's automaticSessionsTrackingStatus
184
+ _ZAP._config.track_session = typeof config.track_session === 'boolean' ? config.track_session : AP_CONFIG.track_session; // no i18n
185
+ // show_logs: the app's own logger lines in the browser console, as Android's showLogs
186
+ _ZAP._config.show_logs = typeof config.show_logs === 'boolean' ? config.show_logs : AP_CONFIG.show_logs; // no i18n
187
+ if (typeof config.ignore_do_not_track === 'boolean') { // no i18n
188
+ _ZAP._config.ignore_do_not_track = config.ignore_do_not_track;
189
+ }
190
+ // debug: debug mode, the debug endpoints. Same payloads, but the answer says where to trace the
191
+ // request. debug_api is its earlier name and still works; debug wins when both are given
192
+ _ZAP._config.debug_api = typeof config.debug === 'boolean' ? config.debug // no i18n
193
+ : typeof config.debug_api === 'boolean' ? config.debug_api : AP_CONFIG.debug_api; // no i18n
194
+ // starts (or clears) the idle hour that closes debug mode on its own
195
+ // an enableDebug() or disableDebug() call the app already made wins over the config
196
+ applyDebugConfig(_ZAP._config.debug_api);
197
+ // what to call this device in the debug stream; see devicename in core/transport.ts
198
+ _ZAP._config.device_name = typeof config.device_name === 'string' ? config.device_name : AP_CONFIG.device_name; // no i18n
199
+ // remote logging: the SDK's own diagnostics, sent to console/addlog
200
+ _ZAP._config.remote_log = AP_CONFIG.remote_log;
201
+ if (typeof config.remote_log === 'boolean') { // no i18n
202
+ _ZAP._config.remote_log = config.remote_log;
203
+ }
204
+ // automatic api tracking: the app's own requests, wrapped. Which hosts it records is
205
+ // configureApiTracking's to say; the two keys that once did it are refused out loud rather
206
+ // than quietly ignored, since an app relying on them would otherwise record hosts it meant not to
207
+ _ZAP._config.track_api = AP_CONFIG.track_api;
208
+ ['track_api_hosts', 'track_api_exclude_hosts'].forEach(function (key) {
209
+ if (config[key] !== undefined) {
210
+ warnAlways('Apptics.init: ' + key + ' is no longer supported; use configureApiTracking(new ApiTrackingBuilder().' // no i18n
211
+ + (key === 'track_api_hosts' ? 'allowOnlyDomains' : 'ignoreDomains') + '(...).build())'); // no i18n
212
+ }
213
+ });
214
+ if (typeof config.track_api === 'boolean') { // no i18n
215
+ _ZAP._config.track_api = config.track_api;
216
+ }
217
+ enableApiTracking(_ZAP._config.track_api);
218
+ // heatmap capture: a no-op unless the app imported the heatmap entry, which sets the hook
219
+ _ZAP._config.track_heatmap = typeof config.track_heatmap === 'boolean' // no i18n
220
+ ? config.track_heatmap
221
+ : AP_CONFIG.track_heatmap;
222
+ hooks.enableHeatmap(_ZAP._config.track_heatmap);
223
+ // automatic screen tracking, on unless the config says false: switched on by start(), once a
224
+ // screen view can be stored
225
+ _ZAP._config.track_screen = typeof config.track_screen === 'boolean' ? config.track_screen : AP_CONFIG.track_screen; // no i18n
226
+ applyIntervals(config);
227
+ lastConfig = config;
228
+ _ZAP._initialised = true;
229
+ _ZAP._ready = false;
230
+ _ZAP._pending = [];
231
+ var myGeneration = ++generation;
232
+ _ZAP._readyPromise = storageReady().then(function (backend) {
233
+ if (myGeneration !== generation) {
234
+ return false;
235
+ }
236
+ if (!backend) {
237
+ warnAlways('Apptics.init: no usable storage (IndexedDB or localStorage), not starting'); // no i18n
238
+ _ZAP._initialised = false;
239
+ _ZAP._token = ''; // no i18n
240
+ _ZAP._pending = [];
241
+ return false;
242
+ }
243
+ discardOtherAppData(_ZAP._defaultoptions);
244
+ // app/addversion is the first call and everything waits on it: it is what turns the four
245
+ // values init() was given into aaid, the portal and project ids every url carries, and
246
+ // appreleaseversionid, which metaWebSDKV2 refuses a payload without
247
+ return registerAppVersion().then(function (registered) {
248
+ if (myGeneration !== generation) {
249
+ return false;
250
+ }
251
+ if (!registered) {
252
+ warnAlways('Apptics.init: app/addversion did not return the app ids, not starting'); // no i18n
253
+ _ZAP._initialised = false;
254
+ _ZAP._token = ''; // no i18n
255
+ _ZAP._pending = [];
256
+ return false;
257
+ }
258
+ return start(config, myGeneration);
259
+ });
260
+ }).catch(function (err) {
261
+ Console.error('Apptics.init: start-up failed', err); // no i18n
262
+ return false;
263
+ });
264
+ return true;
265
+ }
266
+ /** Resolves true once start-up has finished, false if init() refused or storage is unusable. */
267
+ function ready() {
268
+ return _ZAP._readyPromise || Promise.resolve(false);
269
+ }
270
+ function start(config, myGeneration) {
271
+ // app/addversion named the app; data stored for another one was discarded before it ran
272
+ _ZAP._token = String(_ZAP._defaultoptions.aaid);
273
+ user_defaults.add('token', _ZAP._token); // no i18n
274
+ // last known server settings (getupdates) apply before anything is tracked
275
+ restoreServerSettings();
276
+ // required by init(), so _defaultoptions.appversion is always the app's own version, as the
277
+ // text normaliseConfig made of it: there is no default to fall back to, and the stored value
278
+ // below is kept only to notice when the version changes
279
+ var uuid = user_defaults.item('uuid'); // no i18n
280
+ if (isEmpty(uuid)) {
281
+ uuid = getNewUUID();
282
+ user_defaults.add('uuid', uuid); // no i18n
283
+ }
284
+ _ZAP._uuid = uuid;
285
+ var stored_appversion = user_defaults.item('appversion'); // no i18n
286
+ if (isEmpty(stored_appversion)) {
287
+ user_defaults.add('appversion', _ZAP._defaultoptions.appversion); // no i18n
288
+ stored_appversion = _ZAP._defaultoptions.appversion;
289
+ }
290
+ var appVersionChanged = stored_appversion != _ZAP._defaultoptions.appversion;
291
+ _ZAP._ignoreDnt = _ZAP._config.ignore_do_not_track;
292
+ tracking_preference.update_status(getTrackingStatus());
293
+ checkAndUpdateDeviceInfo();
294
+ // returning visit: ask the server for its settings now instead of waiting 2 minutes
295
+ // (first visit: device/add triggers it once the ids exist)
296
+ refreshServerSettings();
297
+ if (appVersionChanged) {
298
+ _ZAP._device_info.appversionid = ''; // no i18n
299
+ updateDeviceWithApptics(_ZAP._device_info).then(function (result) {
300
+ if (isSuccess(result)) {
301
+ user_defaults.add('appversion', _ZAP._defaultoptions.appversion); // no i18n
302
+ Console.log('init: appversion updated to ' + _ZAP._defaultoptions.appversion); // no i18n
303
+ }
304
+ }).catch(function (err) {
305
+ Console.log('init: error updating appversion: ' + err); // no i18n
306
+ });
307
+ }
308
+ // attempt to resolve connection type
309
+ _ZAP._device_info.connectionType = getConnectionType();
310
+ attachListeners();
311
+ _ZAP._properties.orientation = getOrientation();
312
+ getUserInfo();
313
+ return checkAndUpdateSession().then(function () {
314
+ if (myGeneration !== generation) {
315
+ return false;
316
+ }
317
+ startTimers();
318
+ sendStoredLogs();
319
+ _ZAP._ready = true;
320
+ // replay calls made while storage was loading, in order
321
+ var pending = _ZAP._pending;
322
+ _ZAP._pending = [];
323
+ pending.forEach(function (call) {
324
+ try {
325
+ call();
326
+ }
327
+ catch (err) {
328
+ Console.error('apptics: buffered call failed', err); // no i18n
329
+ }
330
+ });
331
+ // after the replay, so a inScreen() the app made during start-up keeps its place, and
332
+ // the first automatic view is the page as it is now
333
+ enableScreenTracking(_ZAP._config.track_screen);
334
+ // a no-op unless the remote-config entry was imported, which sets the hook
335
+ hooks.remoteConfigStarted();
336
+ window.appticsReadyStatus = true;
337
+ if (typeof window.appticsReady == 'function') { // no i18n
338
+ window.appticsReady();
339
+ }
340
+ return true;
341
+ });
342
+ }
343
+ /** Clears stored identity and queues, then starts again from the snippet. */
344
+ function reset() {
345
+ generation++;
346
+ stopTimers();
347
+ // the wrappers come off with everything else; the init() below puts them back if the config
348
+ // asked for them, so a reset that has no config to restore leaves XHR and fetch untouched
349
+ enableApiTracking(false);
350
+ enableScreenTracking(false);
351
+ clearAppVersion();
352
+ hooks.enableHeatmap(false);
353
+ hooks.resetHeatmap();
354
+ hooks.resetRemoteConfig();
355
+ clearStorage();
356
+ _ZAP._initialised = false;
357
+ _ZAP._ready = false;
358
+ _ZAP._pending = [];
359
+ _ZAP._readyPromise = null;
360
+ _ZAP._device_info = {};
361
+ _ZAP._user_info = {};
362
+ _ZAP._current_screen = {};
363
+ _ZAP._current_session = {};
364
+ _ZAP._uuid = ''; // no i18n
365
+ _ZAP._apid = ''; // no i18n
366
+ _ZAP._mapid = ''; // no i18n
367
+ _ZAP._sending = false;
368
+ Console.log('apptics.reset()'); // no i18n
369
+ // start again with the config init() was called with
370
+ if (lastConfig) {
371
+ init(lastConfig);
372
+ }
373
+ }
374
+ function isActive() {
375
+ return _ZAP._ready;
376
+ }
377
+ // Declarative click tracking: <el apeventaction="name" apeventprops='{"k":"v"}'> inside <el apgroupaction="group">
378
+ function onDocumentClick(event) {
379
+ if (!window.appticsReadyStatus || !isActive()) {
380
+ return;
381
+ }
382
+ var start = event.target;
383
+ if (start && typeof start.closest !== 'function') { // no i18n
384
+ start = start.parentElement;
385
+ }
386
+ if (!start) {
387
+ return;
388
+ }
389
+ var targetElem = start.closest('[apeventaction]:not([apeventaction=""])'); // no i18n
390
+ if (!targetElem) {
391
+ return;
392
+ }
393
+ var eventName = targetElem.getAttribute('apeventaction') || ''; // no i18n
394
+ var groupElem = targetElem.closest('[apgroupaction]'); // no i18n
395
+ var groupName = (groupElem && groupElem.getAttribute('apgroupaction')) || AP_CONFIG.default_group_name; // no i18n
396
+ var eventProps = {};
397
+ var rawProps = targetElem.getAttribute('apeventprops'); // no i18n
398
+ if (!isEmpty(rawProps)) {
399
+ try {
400
+ eventProps = JSON.parse(rawProps);
401
+ }
402
+ catch (err) {
403
+ Console.warn('apptics: invalid JSON in apeventprops for "' + eventName + '", sending no properties'); // no i18n
404
+ eventProps = {};
405
+ }
406
+ }
407
+ if (!isEmpty(eventName)) {
408
+ trackEvent(eventName, groupName, eventProps);
409
+ }
410
+ }
411
+ /**
412
+ * Page is in the background but still there: close the open screen and send what's queued.
413
+ * By keepalive, because hidden is often the last moment before the tab closes, and a send still
414
+ * waiting on its answer would hold the queue as pagehide tries to send it.
415
+ */
416
+ function onPageHidden() {
417
+ if (!isActive())
418
+ return;
419
+ updateScreenWithEndtime();
420
+ flush(true);
421
+ Console.log('page hidden: closing the open screen and flushing'); // no i18n
422
+ }
423
+ /**
424
+ * The tab is closing, or the page is being replaced or frozen into the back/forward cache.
425
+ * The session ends here, and everything queued goes out by keepalive, since a normal
426
+ * request would be cancelled with the page.
427
+ */
428
+ function onPageClosing() {
429
+ if (!isActive())
430
+ return;
431
+ Console.log('page closing: ending the session and sending what is queued'); // no i18n
432
+ updateScreenWithEndtime();
433
+ forgetStoredLogs();
434
+ endCurrentSession().then(function () {
435
+ return flush(true);
436
+ });
437
+ }
438
+ function attachListeners() {
439
+ if (listenersAttached) {
440
+ return;
441
+ }
442
+ listenersAttached = true;
443
+ // listen for connection change events (only available in w3c implementation)
444
+ var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection;
445
+ if (connection && connection.addEventListener) {
446
+ connection.addEventListener('change', function () {
447
+ _ZAP._device_info.connectionType = getConnectionType();
448
+ });
449
+ }
450
+ // Track when the window loses focus (user switches to another window or application)
451
+ window.addEventListener('blur', function () {
452
+ if (!isActive())
453
+ return;
454
+ Console.log('Window lost focus, user switched to another window or application'); // no i18n
455
+ updateLastActiveTimeOfSession();
456
+ });
457
+ // Track when the window gains focus (user switches back to the window)
458
+ window.addEventListener('focus', function () {
459
+ if (!isActive())
460
+ return;
461
+ Console.log('Window regained focus, user switched back to the window'); // no i18n
462
+ checkAndUpdateSession();
463
+ startTimers();
464
+ });
465
+ // IndexedDB writes are async, so unload work starts on pagehide rather than beforeunload
466
+ window.addEventListener('pagehide', onPageClosing); // no i18n
467
+ // back/forward cache: pagehide ended the session, so coming back starts a new one
468
+ window.addEventListener('pageshow', function (event) {
469
+ if (!isActive() || !event.persisted)
470
+ return;
471
+ Console.log('restored from the back/forward cache: starting a new session'); // no i18n
472
+ // the screen the page was left on starts a new view, in the new session
473
+ checkAndUpdateSession().then(resumeScreen);
474
+ startTimers();
475
+ });
476
+ document.addEventListener('visibilitychange', function () {
477
+ if (!isActive())
478
+ return;
479
+ if (document.visibilityState === 'hidden') { // no i18n
480
+ onPageHidden();
481
+ return;
482
+ }
483
+ // back in view: the server's tracking flags may have changed while we were away
484
+ Console.log('page visible: refreshing the server settings'); // no i18n
485
+ // hiding ended the screen view; the screen the user is back on starts a new one, after the
486
+ // session is settled so the view belongs to the right one
487
+ checkAndUpdateSession().then(resumeScreen);
488
+ refreshServerSettings();
489
+ });
490
+ // if we are running in cordova use ondeviceready otherwise onload
491
+ window.addEventListener(window.cordova ? 'deviceready' : 'load', function () {
492
+ if (isActive())
493
+ checkAndUpdateSession();
494
+ }, { passive: true });
495
+ // Always send pending requests when the connection comes back online
496
+ window.addEventListener('online', function () {
497
+ if (!isActive())
498
+ return;
499
+ // a first visit that started offline has no device ids yet, and nothing can be sent
500
+ // until it has them: register before flushing, and flush once that has landed
501
+ if (needsDevice()) {
502
+ Console.log('back online: registering this device before sending'); // no i18n
503
+ checkAndUpdateDeviceInfo();
504
+ deviceReady().then(function () {
505
+ if (!isActive())
506
+ return;
507
+ flush();
508
+ // the lines logged while offline are waiting too, and log/add needs the same ids
509
+ sendStoredLogs();
510
+ });
511
+ return;
512
+ }
513
+ flush();
514
+ sendStoredLogs();
515
+ }, { passive: true });
516
+ if (window.screen && window.screen.orientation && typeof window.screen.orientation.addEventListener === 'function') { // no i18n
517
+ window.screen.orientation.addEventListener('change', function () {
518
+ _ZAP._properties.orientation = getOrientation();
519
+ });
520
+ }
521
+ window.addEventListener('unhandledrejection', function (event) {
522
+ if (isActive() && _ZAP._isGlobalErrorTracking) {
523
+ trackError(event);
524
+ }
525
+ });
526
+ window.addEventListener('error', function (event) {
527
+ if (isActive() && _ZAP._isGlobalErrorTracking) {
528
+ trackError(event);
529
+ }
530
+ });
531
+ window.addEventListener('click', onDocumentClick, true); // no i18n
532
+ }
533
+
534
+ export { init, ready, reset };
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
@@ -0,0 +1,10 @@
1
+ /** The value set for a custom criteria key, or undefined when none is. */
2
+ export declare function customConditionValue(key: string): string | undefined;
3
+ /**
4
+ * Sets what this device is for a custom criteria, or removes it with an empty value. Re-applies
5
+ * the stored rules as soon as storage is ready, so the next read sees the new result without a
6
+ * fetch.
7
+ */
8
+ export declare function setCustomConditionValue(key: string, value: string | number | boolean | null | undefined): void;
9
+ /** reset(): forgets the values set on this page; the stored ones go with the rest of storage. */
10
+ export declare function clearCustomConditionValues(): void;
@@ -0,0 +1,74 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { user_defaults, storageReady } from '../core/storage.js';
3
+ import { Console } from '../core/logger.js';
4
+ import { reresolve } from './store.js';
5
+
6
+ /**
7
+ * Custom condition values, as Android's AppticsRemoteConfig.setCustomConditionValue: the app says
8
+ * what this device is for a custom criteria the console defines (a condition key with a list of
9
+ * values), and a condition on that key matches when the value set here is one of the listed ones.
10
+ *
11
+ * AppticsRemoteConfig.setCustomConditionValue('plan_tier', 'gold');
12
+ *
13
+ * The rules are evaluated on the device, so the values have to be here on the next visit too:
14
+ * they are stored, and a value set on this page wins over a stored one. Setting one before
15
+ * storage has loaded — before init(), say — is kept in memory and saved once it has.
16
+ *
17
+ * Assumed wire format, until the server confirms it: a custom criteria arrives with the custom
18
+ * key as its `key` and operator 1 ("is one of"), the same shape as the built-in criteria. A
19
+ * different shape fails closed — the condition does not match and the default is used.
20
+ */
21
+ const STORE_KEY = 'remoteconfig_custom'; // no i18n
22
+ /** This page's values; null marks a key removed here, so a stored value no longer counts. */
23
+ var mine = {};
24
+ function stored() {
25
+ var saved = user_defaults.item(STORE_KEY);
26
+ return saved && typeof saved === 'object' ? saved : {}; // no i18n
27
+ }
28
+ /** The value set for a custom criteria key, or undefined when none is. */
29
+ function customConditionValue(key) {
30
+ if (Object.prototype.hasOwnProperty.call(mine, key)) {
31
+ var here = mine[key];
32
+ return here === null ? undefined : here;
33
+ }
34
+ var saved = stored();
35
+ return Object.prototype.hasOwnProperty.call(saved, key) ? saved[key] : undefined;
36
+ }
37
+ /**
38
+ * Sets what this device is for a custom criteria, or removes it with an empty value. Re-applies
39
+ * the stored rules as soon as storage is ready, so the next read sees the new result without a
40
+ * fetch.
41
+ */
42
+ function setCustomConditionValue(key, value) {
43
+ var name = typeof key === 'string' ? key.trim() : ''; // no i18n
44
+ if (name === '') { // no i18n
45
+ Console.warn('AppticsRemoteConfig.setCustomConditionValue: a condition key is required'); // no i18n
46
+ return;
47
+ }
48
+ var text = value === null || value === undefined ? '' : String(value).trim(); // no i18n
49
+ mine[name] = text === '' ? null : text; // no i18n
50
+ storageReady().then(function (backend) {
51
+ if (!backend) {
52
+ return;
53
+ }
54
+ var saved = stored();
55
+ Object.keys(mine).forEach(function (one) {
56
+ var here = mine[one];
57
+ if (here === null || here === undefined) {
58
+ delete saved[one];
59
+ }
60
+ else {
61
+ saved[one] = here;
62
+ }
63
+ });
64
+ user_defaults.add(STORE_KEY, saved);
65
+ // only once storage has loaded: re-resolving before it would read an empty rule set and keep it
66
+ reresolve();
67
+ });
68
+ }
69
+ /** reset(): forgets the values set on this page; the stored ones go with the rest of storage. */
70
+ function clearCustomConditionValues() {
71
+ mine = {};
72
+ }
73
+
74
+ export { clearCustomConditionValues, customConditionValue, setCustomConditionValue };
@@ -0,0 +1,24 @@
1
+ import type { Dict } from '../types.js';
2
+ /** Forgets what has been complained about, so a new rule set is judged afresh. */
3
+ export declare function resetEvaluationWarnings(): void;
4
+ /**
5
+ * Whether a condition holds: every one of its criteria must. The template requires at least one
6
+ * (`array-size=">=1"`), so a condition with none is malformed and does not match — rather than
7
+ * matching vacuously, which would apply it to every device.
8
+ */
9
+ export declare function conditionMatches(condition: Dict): boolean;
10
+ /**
11
+ * The value of one parameter on this device, as the string the server stores it as.
12
+ *
13
+ * `byId` is every condition the answer carried, keyed by its id — the mapping on the parameter
14
+ * names a condition but does not repeat its criteria.
15
+ */
16
+ export declare function resolve(parameter: Dict, byId: Record<string, Dict>): string;
17
+ /**
18
+ * Every parameter resolved against this device, as a flat name -> value map.
19
+ *
20
+ * Built in one pass and kept, rather than resolved per read: the rule set only changes when a
21
+ * fetch brings a new one, and an app reading twenty flags during a render should not walk every
22
+ * condition twenty times.
23
+ */
24
+ export declare function resolveAll(remoteconfig: Dict): Record<string, string>;