@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,467 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ 'use strict';
3
+
4
+ var logger = require('./logger.js');
5
+ var utils = require('./utils.js');
6
+
7
+ const DB_NAME = 'apptics'; // no i18n
8
+ // 3 added the heatmaps store. 4 renamed: each record's order key `seq` to `queue`, the logs store
9
+ // to feedbacklogs and consolelogs to remotelogs. Every upgrade keeps what is already queued.
10
+ const DB_VERSION = 4;
11
+ const OPEN_TIMEOUT_MS = 3000;
12
+ const QUEUES = ['engagements', 'errors', 'feedbacklogs', 'remotelogs', 'heatmaps']; // no i18n
13
+ /** The field, and the index on it, that keeps a queue's records in the order they were added. */
14
+ const QUEUE_KEY = 'queue'; // no i18n
15
+ /** Version 3's names, which the version 4 upgrade moves to the ones above. */
16
+ const OLD_QUEUE_KEY = 'seq'; // no i18n
17
+ const RENAMED_STORES = [['logs', 'feedbacklogs'], ['consolelogs', 'remotelogs']]; // no i18n
18
+ /** The types a feedback entry is stored under: an addFeedbackLog() line, an addDiagnosticsInfo() entry. */
19
+ const FEEDBACK_LOG = 'feedbacklog'; // no i18n
20
+ const FEEDBACK_DIAGNOSTICS = 'feedbackdiagnostics'; // no i18n
21
+ const OLD_FEEDBACK_TYPES = Object.freeze({
22
+ log: FEEDBACK_LOG, // no i18n
23
+ diagnostics: FEEDBACK_DIAGNOSTICS, // no i18n
24
+ });
25
+ /** A feedback entry from 1.x or 2.0.0-beta, with the type it is stored under now. */
26
+ function renameFeedbackType(item) {
27
+ var renamed = item && typeof item.type === 'string' ? OLD_FEEDBACK_TYPES[item.type] : undefined; // no i18n
28
+ return renamed ? { ...item, type: renamed } : item;
29
+ }
30
+ /** 1.x localStorage keys, read once to bring 1.x data into IndexedDB (see migrateLegacy). */
31
+ const LEGACY_KEYS = Object.freeze({
32
+ settings: 'apptics-device-info', // no i18n
33
+ engagements: 'apptics-engagements-transactions', // no i18n
34
+ errors: 'apptics-errors-transactions', // no i18n
35
+ logs: 'apptics-log-transactions', // no i18n
36
+ consolelogs: 'apptics-consolelog-transactions', // no i18n
37
+ });
38
+ /** The localStorage backend's layout, for a browser where IndexedDB will not open. */
39
+ const LOCAL_KEYS = Object.freeze({
40
+ settings: LEGACY_KEYS.settings,
41
+ engagements: LEGACY_KEYS.engagements,
42
+ errors: LEGACY_KEYS.errors,
43
+ feedbacklogs: 'apptics-feedbacklog-transactions', // no i18n
44
+ remotelogs: 'apptics-remotelog-transactions', // no i18n
45
+ heatmaps: 'apptics-heatmap-transactions', // no i18n
46
+ });
47
+ /**
48
+ * The localStorage backend once kept these two under the 1.x keys. Moved to the new ones on first
49
+ * use, feedback types renamed on the way, unless something is already there.
50
+ */
51
+ function moveRenamedLocalKeys() {
52
+ [[LEGACY_KEYS.logs, LOCAL_KEYS.feedbacklogs], [LEGACY_KEYS.consolelogs, LOCAL_KEYS.remotelogs]].forEach(function (pair) {
53
+ try {
54
+ var from = pair[0];
55
+ var to = pair[1];
56
+ var old = localStorage.getItem(from);
57
+ if (old === null) {
58
+ return;
59
+ }
60
+ if (localStorage.getItem(to) === null) {
61
+ var items = asList(JSON.parse(old));
62
+ localStorage.setItem(to, JSON.stringify(to === LOCAL_KEYS.feedbacklogs ? items.map(renameFeedbackType) : items));
63
+ }
64
+ localStorage.removeItem(from);
65
+ }
66
+ catch (err) {
67
+ // left where it is; the next load tries again
68
+ }
69
+ });
70
+ }
71
+ /** Shape guards shared by both backends and the 1.x migration. */
72
+ function asList(value) {
73
+ return Array.isArray(value) ? value : [];
74
+ }
75
+ function asDict(value) {
76
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
77
+ }
78
+ /* ---------------- localStorage backend ---------------- */
79
+ function readJSON(key) {
80
+ try {
81
+ const raw = localStorage.getItem(key);
82
+ return raw === null || raw === '' ? null : JSON.parse(raw); // no i18n
83
+ }
84
+ catch (err) {
85
+ logger.Console.warn('apptics: could not read ' + key + ', treating it as empty'); // no i18n
86
+ return null;
87
+ }
88
+ }
89
+ function writeJSON(key, value) {
90
+ try {
91
+ localStorage.setItem(key, JSON.stringify(value));
92
+ }
93
+ catch (err) {
94
+ logger.Console.warn('apptics: could not write ' + key + ': ' + String(err)); // no i18n
95
+ }
96
+ }
97
+ function createLocalStorageBackend() {
98
+ moveRenamedLocalKeys();
99
+ return {
100
+ kind: 'localstorage', // no i18n
101
+ loadSettings() {
102
+ return Promise.resolve(asDict(readJSON(LOCAL_KEYS.settings)));
103
+ },
104
+ putSetting(key, value) {
105
+ const all = asDict(readJSON(LOCAL_KEYS.settings));
106
+ all[key] = value;
107
+ writeJSON(LOCAL_KEYS.settings, all);
108
+ return Promise.resolve();
109
+ },
110
+ deleteSetting(key) {
111
+ const all = asDict(readJSON(LOCAL_KEYS.settings));
112
+ delete all[key];
113
+ writeJSON(LOCAL_KEYS.settings, all);
114
+ return Promise.resolve();
115
+ },
116
+ clearSettings() {
117
+ writeJSON(LOCAL_KEYS.settings, {});
118
+ return Promise.resolve();
119
+ },
120
+ queueAll(store) {
121
+ return Promise.resolve(asList(readJSON(LOCAL_KEYS[store])));
122
+ },
123
+ queuePut(store, items) {
124
+ const list = asList(readJSON(LOCAL_KEYS[store]));
125
+ items.forEach(function (item) {
126
+ const index = list.findIndex(function (existing) { return existing.id === item.id; });
127
+ if (index === -1) {
128
+ list.push(item);
129
+ }
130
+ else {
131
+ list[index] = item;
132
+ }
133
+ });
134
+ writeJSON(LOCAL_KEYS[store], list);
135
+ return Promise.resolve();
136
+ },
137
+ queueDelete(store, ids) {
138
+ const remaining = asList(readJSON(LOCAL_KEYS[store])).filter(function (item) {
139
+ return ids.indexOf(item.id) === -1;
140
+ });
141
+ writeJSON(LOCAL_KEYS[store], remaining);
142
+ return Promise.resolve();
143
+ },
144
+ queueClear(store) {
145
+ writeJSON(LOCAL_KEYS[store], []);
146
+ return Promise.resolve();
147
+ },
148
+ };
149
+ }
150
+ let lastQueue = 0;
151
+ /**
152
+ * Strictly increasing, and time-based so tabs interleave in roughly the right order.
153
+ * Counting up from the last value rather than a counter that wraps keeps insertion order
154
+ * even when a chatty caller adds more than a thousand items inside one millisecond.
155
+ */
156
+ function nextQueue() {
157
+ const base = utils.nowMs() * 1000;
158
+ lastQueue = base > lastQueue ? base : lastQueue + 1;
159
+ return lastQueue;
160
+ }
161
+ function request(req) {
162
+ return new Promise(function (resolve, reject) {
163
+ req.onsuccess = function () { resolve(req.result); };
164
+ req.onerror = function () { reject(req.error); };
165
+ });
166
+ }
167
+ function completed(tx) {
168
+ return new Promise(function (resolve, reject) {
169
+ tx.oncomplete = function () { resolve(); };
170
+ tx.onerror = function () { reject(tx.error); };
171
+ tx.onabort = function () { reject(tx.error); };
172
+ });
173
+ }
174
+ /**
175
+ * The record's `type` for an item with none of its own: heatmap records carry no type, since
176
+ * their payload is the item itself and the server takes no extra field. Never undefined.
177
+ */
178
+ const STORE_TYPES = Object.freeze({
179
+ engagements: 'engagement', // no i18n
180
+ errors: 'error', // no i18n
181
+ feedbacklogs: FEEDBACK_LOG,
182
+ remotelogs: 'remotelog', // no i18n
183
+ heatmaps: 'heatmap', // no i18n
184
+ });
185
+ function recordType(storeName, item) {
186
+ return item && typeof item.type === 'string' && item.type !== '' ? item.type : (STORE_TYPES[storeName] || storeName); // no i18n
187
+ }
188
+ /** Puts `item` unless it exists (keepExisting) or replaces it keeping its place. Runs inside `store`'s transaction. */
189
+ function putRecord(store, item, keepExisting) {
190
+ const id = String(item.id);
191
+ const lookup = store.get(id);
192
+ lookup.onsuccess = function () {
193
+ const existing = lookup.result;
194
+ if (existing && keepExisting) {
195
+ return;
196
+ }
197
+ store.put({ id: id, queue: existing ? existing.queue : nextQueue(), type: recordType(store.name, item), item: item });
198
+ };
199
+ }
200
+ /** Our stores, as created by onupgradeneeded. */
201
+ function hasAllStores(db) {
202
+ return db.objectStoreNames.contains('settings') && QUEUES.every(function (name) {
203
+ return db.objectStoreNames.contains(name);
204
+ });
205
+ }
206
+ function deleteDatabase(factory) {
207
+ return new Promise(function (resolve) {
208
+ var req = factory.deleteDatabase(DB_NAME);
209
+ req.onsuccess = function () { resolve(); };
210
+ req.onerror = function () { resolve(); };
211
+ req.onblocked = function () { resolve(); };
212
+ });
213
+ }
214
+ /**
215
+ * Opens the database, and repairs it once if something else created an "apptics" database
216
+ * without our stores (then onupgradeneeded never fires and every read would fail).
217
+ */
218
+ function openIndexedDB(factory = indexedDB, timeoutMs = OPEN_TIMEOUT_MS) {
219
+ return openOnce(factory, timeoutMs).then(function (db) {
220
+ if (hasAllStores(db)) {
221
+ return db;
222
+ }
223
+ logger.Console.warn('apptics: the "' + DB_NAME + '" database is missing its stores, recreating it'); // no i18n
224
+ db.close();
225
+ return deleteDatabase(factory).then(function () {
226
+ return openOnce(factory, timeoutMs);
227
+ }).then(function (fresh) {
228
+ if (!hasAllStores(fresh)) {
229
+ fresh.close();
230
+ throw new Error('indexedDB: stores could not be created'); // no i18n
231
+ }
232
+ return fresh;
233
+ });
234
+ });
235
+ }
236
+ function openOnce(factory, timeoutMs) {
237
+ return new Promise(function (resolve, reject) {
238
+ let settled = false;
239
+ const fail = function (reason) {
240
+ if (!settled) {
241
+ settled = true;
242
+ clearTimeout(timer);
243
+ reject(reason);
244
+ }
245
+ };
246
+ const timer = setTimeout(function () {
247
+ fail(new Error('indexedDB open timed out')); // no i18n
248
+ }, timeoutMs);
249
+ let req;
250
+ try {
251
+ req = factory.open(DB_NAME, DB_VERSION);
252
+ }
253
+ catch (err) {
254
+ fail(err);
255
+ return;
256
+ }
257
+ req.onupgradeneeded = function () {
258
+ upgrade(req.result, req.transaction);
259
+ };
260
+ req.onsuccess = function () {
261
+ if (settled) {
262
+ req.result.close(); // we already gave up (timeout or blocked)
263
+ return;
264
+ }
265
+ settled = true;
266
+ clearTimeout(timer);
267
+ // Another tab running a newer build needs to upgrade the schema, and cannot while this
268
+ // connection is open. Letting go is the only cooperative answer: holding on blocks that
269
+ // tab's upgrade until this one is closed, and it spends the whole time with no storage.
270
+ // This tab keeps working from memory and picks the new schema up on its next load.
271
+ req.result.onversionchange = function () {
272
+ logger.Console.warn('apptics: another tab is upgrading the database, closing this connection'); // no i18n
273
+ req.result.close();
274
+ };
275
+ resolve(req.result);
276
+ };
277
+ req.onerror = function () {
278
+ fail(req.error);
279
+ };
280
+ req.onblocked = function () {
281
+ // Another tab is holding an older version open. A build that sets onversionchange
282
+ // (above) lets go by itself, so this resolves on its own in a moment; the open is left
283
+ // to run until the timeout rather than abandoned, because giving up here would mean
284
+ // running with no storage for the rest of the visit.
285
+ logger.Console.warn('apptics: waiting for another tab to release the database'); // no i18n
286
+ };
287
+ });
288
+ }
289
+ /**
290
+ * Creates what is missing and moves version 3's data to version 4's names, inside the upgrade's
291
+ * own transaction: either the whole upgrade lands, or the database stays at the old version with
292
+ * everything still in it.
293
+ */
294
+ function upgrade(db, tx) {
295
+ if (!db.objectStoreNames.contains('settings')) { // no i18n
296
+ db.createObjectStore('settings'); // no i18n
297
+ }
298
+ QUEUES.forEach(function (name) {
299
+ if (!db.objectStoreNames.contains(name)) {
300
+ db.createObjectStore(name, { keyPath: 'id' }).createIndex(QUEUE_KEY, QUEUE_KEY); // no i18n
301
+ }
302
+ });
303
+ // kept stores: the order key is renamed on every record, and the index with it
304
+ QUEUES.forEach(function (name) {
305
+ const store = tx.objectStore(name);
306
+ if (!store.indexNames.contains(OLD_QUEUE_KEY)) {
307
+ return;
308
+ }
309
+ store.deleteIndex(OLD_QUEUE_KEY);
310
+ if (!store.indexNames.contains(QUEUE_KEY)) {
311
+ store.createIndex(QUEUE_KEY, QUEUE_KEY);
312
+ }
313
+ eachRecord(store, function (record, cursor) {
314
+ cursor.update(renamedRecord(record, false, name));
315
+ });
316
+ });
317
+ // renamed stores: every record moves to its new store, then the old store goes
318
+ RENAMED_STORES.forEach(function (pair) {
319
+ const from = pair[0];
320
+ const to = pair[1];
321
+ if (!db.objectStoreNames.contains(from)) {
322
+ return;
323
+ }
324
+ const source = tx.objectStore(from);
325
+ const target = tx.objectStore(to);
326
+ eachRecord(source, function (record) {
327
+ target.put(renamedRecord(record, to === 'feedbacklogs', to)); // no i18n
328
+ }, function () {
329
+ db.deleteObjectStore(from);
330
+ });
331
+ });
332
+ }
333
+ /** Calls `each` for every record of `store`, then `done`, inside the transaction `store` is in. */
334
+ function eachRecord(store, each, done) {
335
+ const req = store.openCursor();
336
+ req.onsuccess = function () {
337
+ const cursor = req.result;
338
+ if (!cursor) {
339
+ if (done)
340
+ done();
341
+ return;
342
+ }
343
+ each(cursor.value, cursor);
344
+ cursor.continue();
345
+ };
346
+ }
347
+ /** A version 3 record under version 4's names: `queue` for `seq`, and the feedback types renamed. */
348
+ function renamedRecord(record, feedback, storeName) {
349
+ const queue = typeof record[QUEUE_KEY] === 'number' ? record[QUEUE_KEY] : (typeof record[OLD_QUEUE_KEY] === 'number' ? record[OLD_QUEUE_KEY] : nextQueue()); // no i18n
350
+ const item = (feedback ? renameFeedbackType(record.item) : record.item);
351
+ return { id: String(record.id), queue: queue, type: recordType(storeName, item), item: item };
352
+ }
353
+ function createIndexedDBBackend(db) {
354
+ return {
355
+ kind: 'indexeddb', // no i18n
356
+ loadSettings() {
357
+ const store = db.transaction('settings', 'readonly').objectStore('settings'); // no i18n
358
+ return Promise.all([request(store.getAllKeys()), request(store.getAll())]).then(function ([keys, values]) {
359
+ const out = {};
360
+ keys.forEach(function (key, i) {
361
+ out[String(key)] = values[i];
362
+ });
363
+ return out;
364
+ });
365
+ },
366
+ putSetting(key, value) {
367
+ const tx = db.transaction('settings', 'readwrite'); // no i18n
368
+ tx.objectStore('settings').put(value, key); // no i18n
369
+ return completed(tx);
370
+ },
371
+ deleteSetting(key) {
372
+ const tx = db.transaction('settings', 'readwrite'); // no i18n
373
+ tx.objectStore('settings').delete(key); // no i18n
374
+ return completed(tx);
375
+ },
376
+ clearSettings() {
377
+ const tx = db.transaction('settings', 'readwrite'); // no i18n
378
+ tx.objectStore('settings').clear(); // no i18n
379
+ return completed(tx);
380
+ },
381
+ queueAll(store) {
382
+ const index = db.transaction(store, 'readonly').objectStore(store).index(QUEUE_KEY);
383
+ return request(index.getAll()).then(function (records) {
384
+ return records.map(function (record) { return record.item; });
385
+ });
386
+ },
387
+ queuePut(store, items) {
388
+ const tx = db.transaction(store, 'readwrite'); // no i18n
389
+ const objectStore = tx.objectStore(store);
390
+ items.forEach(function (item) { putRecord(objectStore, item, false); });
391
+ return completed(tx);
392
+ },
393
+ queueDelete(store, ids) {
394
+ const tx = db.transaction(store, 'readwrite'); // no i18n
395
+ const objectStore = tx.objectStore(store);
396
+ ids.forEach(function (id) { objectStore.delete(id); });
397
+ return completed(tx);
398
+ },
399
+ queueClear(store) {
400
+ const tx = db.transaction(store, 'readwrite'); // no i18n
401
+ tx.objectStore(store).clear();
402
+ return completed(tx);
403
+ },
404
+ importAll(settings, queues) {
405
+ // scope derived from QUEUES, not repeated: the loop below opens every one of them,
406
+ // and a store left out of the scope throws NotFoundError the moment it is reached
407
+ const tx = db.transaction(['settings'].concat(QUEUES), 'readwrite'); // no i18n
408
+ const settingsStore = tx.objectStore('settings'); // no i18n
409
+ Object.keys(settings).forEach(function (key) {
410
+ const lookup = settingsStore.get(key);
411
+ lookup.onsuccess = function () {
412
+ if (lookup.result === undefined) {
413
+ settingsStore.put(settings[key], key);
414
+ }
415
+ };
416
+ });
417
+ QUEUES.forEach(function (name) {
418
+ const objectStore = tx.objectStore(name);
419
+ queues[name].forEach(function (item) { putRecord(objectStore, item, true); });
420
+ });
421
+ return completed(tx);
422
+ },
423
+ };
424
+ }
425
+ function localStorageUsable() {
426
+ try {
427
+ const probe = '__apptics_probe__'; // no i18n
428
+ localStorage.setItem(probe, '1');
429
+ localStorage.removeItem(probe);
430
+ return true;
431
+ }
432
+ catch (err) {
433
+ return false;
434
+ }
435
+ }
436
+ /** IndexedDB when it opens, otherwise localStorage, otherwise null. Never rejects. */
437
+ function openBackend() {
438
+ const fallback = function (reason) {
439
+ logger.Console.warn('apptics: IndexedDB unavailable (' + String(reason) + '), using localStorage'); // no i18n
440
+ return localStorageUsable() ? createLocalStorageBackend() : null;
441
+ };
442
+ let factory;
443
+ try {
444
+ factory = typeof indexedDB !== 'undefined' ? indexedDB : undefined; // no i18n
445
+ }
446
+ catch (err) {
447
+ factory = undefined; // access can throw in sandboxed frames
448
+ }
449
+ if (!factory) {
450
+ return Promise.resolve(fallback('not supported')); // no i18n
451
+ }
452
+ return openIndexedDB(factory).then(createIndexedDBBackend, fallback);
453
+ }
454
+
455
+ exports.DB_NAME = DB_NAME;
456
+ exports.DB_VERSION = DB_VERSION;
457
+ exports.FEEDBACK_DIAGNOSTICS = FEEDBACK_DIAGNOSTICS;
458
+ exports.FEEDBACK_LOG = FEEDBACK_LOG;
459
+ exports.LEGACY_KEYS = LEGACY_KEYS;
460
+ exports.LOCAL_KEYS = LOCAL_KEYS;
461
+ exports.asDict = asDict;
462
+ exports.asList = asList;
463
+ exports.createIndexedDBBackend = createIndexedDBBackend;
464
+ exports.createLocalStorageBackend = createLocalStorageBackend;
465
+ exports.openBackend = openBackend;
466
+ exports.openIndexedDB = openIndexedDB;
467
+ exports.renameFeedbackType = renameFeedbackType;
@@ -0,0 +1,22 @@
1
+ /** Whether debug mode is on right now, idle hour included. */
2
+ export declare function debugEnabled(): boolean;
3
+ /**
4
+ * Pushes the idle hour out. Called wherever something is actually tracked, which is the only
5
+ * evidence the SDK has that a person is still looking — there is no event for "watching".
6
+ */
7
+ export declare function noteDebugActivity(): void;
8
+ /**
9
+ * Turns debug mode off if its hour has run out. Called from the flush timer, which ticks whether
10
+ * or not anything is happening — a check that only ran on the way into a request would never
11
+ * fire, because an idle SDK makes no requests.
12
+ */
13
+ export declare function expireDebugIfIdle(): void;
14
+ /**
15
+ * Turns debug mode on, at any time: before init(), during start-up or while the SDK runs. The
16
+ * choice holds over `debug` in init() for the rest of the page's life.
17
+ */
18
+ export declare function enableDebug(): void;
19
+ /** Turns debug mode off, at any time, with the same hold over `debug` as enableDebug(). */
20
+ export declare function disableDebug(): void;
21
+ /** What init() applies for `debug`: the config's value, unless the app has already chosen. */
22
+ export declare function applyDebugConfig(configured: boolean): void;
@@ -0,0 +1,88 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ 'use strict';
3
+
4
+ var constants = require('./constants.js');
5
+ var state = require('./state.js');
6
+ var logger = require('./logger.js');
7
+ var utils = require('./utils.js');
8
+
9
+ /**
10
+ * The switch for debug mode, and the hour that closes it.
11
+ *
12
+ * Debug mode is not free on either side: every engagement, exception and log call goes to its
13
+ * `debug/` twin instead of the ordinary endpoint, which makes the server keep a traceable
14
+ * record of the request. That is worth it while someone is watching, and pure
15
+ * cost once they have walked away — and walking away is the normal way a debugging session ends,
16
+ * not a deliberate switch-off. So the SDK closes it: an hour with nothing tracked turns debug
17
+ * back off by itself, and anything tracked pushes that hour out again.
18
+ *
19
+ * It lives in core because every send asks it: `debug: true` in init(), or enableDebug(), is
20
+ * enough to turn the twins on, and that alone must expire.
21
+ */
22
+ /** Whether debug mode is on right now, idle hour included. */
23
+ function debugEnabled() {
24
+ return state._ZAP._config.debug_api === true && !debugIdle();
25
+ }
26
+ /** True once the idle hour has run out on a debug session nobody is watching. */
27
+ function debugIdle() {
28
+ return state._ZAP._debugUntil > 0 && utils.nowMs() > state._ZAP._debugUntil;
29
+ }
30
+ /**
31
+ * Pushes the idle hour out. Called wherever something is actually tracked, which is the only
32
+ * evidence the SDK has that a person is still looking — there is no event for "watching".
33
+ */
34
+ function noteDebugActivity() {
35
+ if (state._ZAP._config.debug_api !== true) {
36
+ return;
37
+ }
38
+ state._ZAP._debugUntil = utils.nowMs() + constants.DEBUG_IDLE_MS;
39
+ }
40
+ /**
41
+ * Turns debug mode off if its hour has run out. Called from the flush timer, which ticks whether
42
+ * or not anything is happening — a check that only ran on the way into a request would never
43
+ * fire, because an idle SDK makes no requests.
44
+ */
45
+ function expireDebugIfIdle() {
46
+ if (!debugIdle()) {
47
+ return;
48
+ }
49
+ logger.Console.log('apptics: debug mode has been idle for an hour, switching it off'); // no i18n
50
+ setDebug(false);
51
+ }
52
+ /**
53
+ * The app's own choice, from enableDebug() or disableDebug(). It wins over `debug` in init(),
54
+ * so debug mode can be switched on or off with one call, before init() runs or while the SDK is
55
+ * running, and an init() or reset() that comes after doesn't switch it back. null until the app
56
+ * has chosen.
57
+ */
58
+ var chosen = null;
59
+ /** Turning it on starts the idle hour; turning it off clears it, so the next on gets a whole hour. */
60
+ function setDebug(on) {
61
+ state._ZAP._config.debug_api = on;
62
+ state._ZAP._debugUntil = on ? utils.nowMs() + constants.DEBUG_IDLE_MS : 0;
63
+ logger.Console.log('apptics: debug mode ' + (on ? 'on' : 'off')); // no i18n
64
+ }
65
+ /**
66
+ * Turns debug mode on, at any time: before init(), during start-up or while the SDK runs. The
67
+ * choice holds over `debug` in init() for the rest of the page's life.
68
+ */
69
+ function enableDebug() {
70
+ chosen = true;
71
+ setDebug(true);
72
+ }
73
+ /** Turns debug mode off, at any time, with the same hold over `debug` as enableDebug(). */
74
+ function disableDebug() {
75
+ chosen = false;
76
+ setDebug(false);
77
+ }
78
+ /** What init() applies for `debug`: the config's value, unless the app has already chosen. */
79
+ function applyDebugConfig(configured) {
80
+ setDebug(chosen !== null ? chosen : configured);
81
+ }
82
+
83
+ exports.applyDebugConfig = applyDebugConfig;
84
+ exports.debugEnabled = debugEnabled;
85
+ exports.disableDebug = disableDebug;
86
+ exports.enableDebug = enableDebug;
87
+ exports.expireDebugIfIdle = expireDebugIfIdle;
88
+ exports.noteDebugActivity = noteDebugActivity;
@@ -0,0 +1,28 @@
1
+ import type { AppticsConfig } from '../types.js';
2
+ export declare function isBlockedWS(ua: string): boolean;
3
+ /** Device RAM as the API wants it ("4 GB"). Chromium only; empty elsewhere. */
4
+ export declare function getRam(): string;
5
+ export declare function getConnectionType(): string;
6
+ export declare function getNetworkStatus(): number;
7
+ /**
8
+ * The battery as a whole percentage, or null where the browser will not say.
9
+ *
10
+ * feedbackWebSDK types `battery` as an int and the console shows it next to a report, which is
11
+ * what makes "it died while I was filling this in" legible. The Battery Status API is behind a
12
+ * promise and is absent in Firefox and Safari entirely, so this answers null rather than 0 -
13
+ * a real 0% and "no answer" are different things, and only one of them belongs in a report.
14
+ */
15
+ export declare function getBatteryPercent(): Promise<number | null>;
16
+ export declare function getOrientation(): number;
17
+ export declare function getDevice(): string;
18
+ export declare function getOS(): string;
19
+ export declare function getBrowser(): string;
20
+ export declare function getBrowserVersion(): number | string;
21
+ export declare function getReferringURL(): string;
22
+ export declare function getTimeZone(): string;
23
+ /** True for crawlers and non-browser environments; the SDK does nothing for them. */
24
+ export declare function is_apptics_disabled(): boolean;
25
+ /** Pure DNT check (no side effects). consent.hasDoNotTrackEnabled() applies NO_TRACKING. */
26
+ export declare function isDntOn(): boolean;
27
+ /** The console snippet's config (window.appticssettings._defaultoptions), if the page defines one. */
28
+ export declare function getSnippetOptions(): AppticsConfig | undefined;