@zoho_apptics/apptics-js-sdk 1.0.1 → 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 -3817
@@ -0,0 +1,425 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { API_VERSIONS, PATHS_WITHOUT_ORG, DEFAULT_API_PATHS, DEBUG_CAPABLE_PATHS, AP_TRACKING_STATUS, DEVICE_NAME_MAX } from './constants.js';
3
+ import { getConfig, _ZAP } from './state.js';
4
+ import { Console } from './logger.js';
5
+ import { isEmpty, isSuccess } from './utils.js';
6
+ import { getKeyFromDeviceInfo } from './storage.js';
7
+ import { is_apptics_disabled } from './env.js';
8
+ import { opt_in_status } from './consent.js';
9
+ import { beginAttempt, attemptSucceeded } from './attempts.js';
10
+ import { debugEnabled } from './debug.js';
11
+ import { hooks } from './hooks.js';
12
+
13
+ /**
14
+ * How long a request may take before it counts as failed. Without a limit a request the network
15
+ * never answers keeps its caller waiting for good, and with it the queue it was sending.
16
+ */
17
+ const REQUEST_TIMEOUT_MS = 30000;
18
+ // Function to make an asynchronous request
19
+ function makeRequest(url, method, payload, headers) {
20
+ return new Promise((resolve, reject) => {
21
+ let xhr = new XMLHttpRequest();
22
+ xhr.open(method, url);
23
+ if (headers) {
24
+ Object.keys(headers).forEach((key) => {
25
+ xhr.setRequestHeader(key, headers[key]);
26
+ });
27
+ }
28
+ xhr.withCredentials = false;
29
+ xhr.timeout = REQUEST_TIMEOUT_MS;
30
+ xhr.onreadystatechange = function () {
31
+ if (xhr.readyState === 4) { // XMLHttpRequest.DONE == 4, except in safari 4
32
+ if (xhr.status == 200) {
33
+ resolve(xhr.responseText);
34
+ }
35
+ else {
36
+ reject(xhr.statusText);
37
+ }
38
+ }
39
+ };
40
+ xhr.onerror = function () {
41
+ reject('makeRequest: Network Error'); // no i18n
42
+ };
43
+ xhr.ontimeout = function () {
44
+ reject('makeRequest: timed out after ' + REQUEST_TIMEOUT_MS + ' ms'); // no i18n
45
+ };
46
+ xhr.send(payload);
47
+ });
48
+ }
49
+ function getHeaderParams(key) {
50
+ if (key == 'zak') { // no i18n
51
+ return _ZAP._defaultoptions.zak;
52
+ }
53
+ else if (key == 'uuid') { // no i18n
54
+ return _ZAP._uuid;
55
+ }
56
+ else if (key == 'apid') { // no i18n
57
+ return _ZAP._apid || getKeyFromDeviceInfo(key);
58
+ }
59
+ else if (key == 'mapid') { // no i18n
60
+ return _ZAP._mapid || getKeyFromDeviceInfo(key);
61
+ }
62
+ else {
63
+ return ''; // no i18n
64
+ }
65
+ }
66
+ /**
67
+ * appversionid and frameworkid, which every v2 url but app/addversion declares min-occurrences="1".
68
+ *
69
+ * They are appended whatever else the path carries, including on a call made before the device is
70
+ * registered: leaving a mandatory param out gets the request refused for *that* param, which sends
71
+ * whoever reads the error looking for the wrong fault. frameworkid falls back to the SDK's own id
72
+ * because device_info has none until the first device/add answers.
73
+ *
74
+ * Returned with a leading separator chosen by the caller's query, so it appends to '' as well as
75
+ * to an existing '?...' string.
76
+ */
77
+ function mandatoryParams(existing) {
78
+ var out = ''; // no i18n
79
+ var appversionid = _ZAP._device_info.appversionid;
80
+ var frameworkid = !isEmpty(_ZAP._device_info.frameworkid) ? _ZAP._device_info.frameworkid : _ZAP._frameworkID;
81
+ if (!isEmpty(appversionid)) {
82
+ out += '&appversionid=' + encodeURIComponent(String(appversionid)); // no i18n
83
+ }
84
+ if (!isEmpty(frameworkid)) {
85
+ out += '&frameworkid=' + encodeURIComponent(String(frameworkid)); // no i18n
86
+ }
87
+ if (out === '') {
88
+ return out;
89
+ }
90
+ // '&...' becomes '?...' when it is the whole query
91
+ return (existing === undefined || existing === '') ? '?' + out.slice(1) : out;
92
+ }
93
+ /**
94
+ * A label for this device built from what we already know about it: "Chrome 141 on macOS".
95
+ *
96
+ * safe_string accepts letters, digits and spaces, so nothing here needs escaping beyond the
97
+ * encoding every param gets. Parts we do not have are left out rather than written as 'unknown',
98
+ * which would read as a name in the list.
99
+ */
100
+ function derivedDeviceName() {
101
+ var info = _ZAP._device_info;
102
+ var browser = isEmpty(info.browser) ? '' : String(info.browser); // no i18n
103
+ var version = isEmpty(info.browserversion) ? '' : String(info.browserversion); // no i18n
104
+ var os = isEmpty(info.osversion) ? '' : String(info.osversion); // no i18n
105
+ var name = browser === '' ? '' : (version === '' ? browser : browser + ' ' + version); // no i18n
106
+ if (os === '') {
107
+ return name;
108
+ }
109
+ return name === '' ? os : name + ' on ' + os; // no i18n
110
+ }
111
+ /**
112
+ * `devicename`, which only engagement, exception and log declare. It is how the debug stream
113
+ * tells one tester's browser from another's, so it is sent when the app named this device, and
114
+ * otherwise only while tracing, where a derived label beats an unnamed row. safe_string needs at
115
+ * least one character, so an empty name is left out rather than sent as ''.
116
+ */
117
+ function deviceNameParam(path, existing) {
118
+ if (!DEBUG_CAPABLE_PATHS[path]) {
119
+ return ''; // no i18n
120
+ }
121
+ var given = getConfig('device_name'); // no i18n
122
+ var name = !isEmpty(given) ? String(given) : (debugEnabled() ? derivedDeviceName() : ''); // no i18n
123
+ if (name === '') {
124
+ return ''; // no i18n
125
+ }
126
+ var param = 'devicename=' + encodeURIComponent(name.slice(0, DEVICE_NAME_MAX)); // no i18n
127
+ return (existing === '' ? '?' : '&') + param; // no i18n
128
+ }
129
+ function getParameters(path) {
130
+ let returnVal = ''; // no i18n
131
+ // app/addversion runs before any id exists: it identifies the build, not the device
132
+ if (path == 'addversion') { // no i18n
133
+ var frameworkid = !isEmpty(_ZAP._device_info.frameworkid) ? _ZAP._device_info.frameworkid : _ZAP._frameworkID;
134
+ return '?version=' + encodeURIComponent(_ZAP._defaultoptions.appversion)
135
+ + '&platform=' + encodeURIComponent(_ZAP._platform)
136
+ + '&identifier=' + encodeURIComponent(_ZAP._defaultoptions.identifier)
137
+ + '&frameworkid=' + encodeURIComponent(String(frameworkid)); // no i18n
138
+ }
139
+ // v2 device/add declares neither identifier, platform nor appversion: the build is already
140
+ // known from app/addversion, and sending an undeclared param is refused as EXTRA_PARAM_FOUND.
141
+ // What it does declare as mandatory is appversionid, which v1 treated as optional.
142
+ if (path == 'regdevice') { // no i18n
143
+ returnVal = '?isanonrequired=' + _ZAP._isanonrequired + '&devicestatus=' + _ZAP._devicestatus; // no i18n
144
+ if (!isEmpty(_ZAP._device_info.deviceid)) {
145
+ returnVal += '&deviceid=' + encodeURIComponent(String(_ZAP._device_info.deviceid)); // no i18n
146
+ }
147
+ return returnVal + mandatoryParams(returnVal);
148
+ }
149
+ // getsdkconfig is the one call that must NOT carry deviceid: it declares the param with
150
+ // decrypt-label="authenticate", which a web SDK cannot satisfy, and sending it is answered
151
+ // with NOT_AUTHENTICATED. getupdates declares the same param with plain paramdecrypt, so it
152
+ // does carry one. It still needs appversionid and frameworkid, added at the end.
153
+ var identifiesDevice = path != 'sdkconfig'; // no i18n
154
+ if (identifiesDevice) {
155
+ if (isEmpty(_ZAP._device_info.deviceid)) {
156
+ hooks.refreshDeviceInfo();
157
+ // the device is missing, but appversionid and frameworkid are mandatory regardless:
158
+ // dropping them turns one missing id into a refusal that names the wrong param
159
+ return returnVal + mandatoryParams(returnVal);
160
+ }
161
+ returnVal = '?deviceid=' + encodeURIComponent(String(_ZAP._device_info.deviceid)); // no i18n
162
+ }
163
+ // feedback is attributed to whoever the form's user picker selected, not to the active user:
164
+ // the person reporting may not be the one the app last registered, and may choose Anonymous
165
+ if (path === 'feedback') { // no i18n
166
+ var picked = hooks.feedbackUser();
167
+ if (picked) {
168
+ returnVal += '&userid=' + encodeURIComponent(String(picked.userid)); // no i18n
169
+ if (!isEmpty(picked.groupid)) {
170
+ returnVal += '&customergroupid=' + encodeURIComponent(String(picked.groupid)); // no i18n
171
+ }
172
+ }
173
+ return returnVal + mandatoryParams(returnVal);
174
+ }
175
+ // add userid and groupid if opt_in_status is USAGE_TRACKING_WITH_PII
176
+ if (path != 'reguser' && identifiesDevice) { // no i18n
177
+ if (opt_in_status() == AP_TRACKING_STATUS.USAGE_TRACKING_WITH_PII) {
178
+ if (_ZAP._user_info.hasOwnProperty('userid') && !isEmpty(_ZAP._user_info.userid)) { // no i18n
179
+ returnVal += '&userid=' + encodeURIComponent(String(_ZAP._user_info.userid)); // no i18n
180
+ }
181
+ if (_ZAP._user_info.hasOwnProperty('groupid') && !isEmpty(_ZAP._user_info.groupid)) { // no i18n
182
+ returnVal += '&customergroupid=' + encodeURIComponent(String(_ZAP._user_info.groupid)); // no i18n
183
+ }
184
+ }
185
+ }
186
+ returnVal += deviceNameParam(path, returnVal);
187
+ return returnVal + mandatoryParams(returnVal);
188
+ }
189
+ /**
190
+ * `extra` appends params the path needs per call rather than per state, which console/addlog does
191
+ * (happenedtime and module change with every line). Values are encoded; the keys are our own.
192
+ */
193
+ function getUrlWithParams(path, extra) {
194
+ var base = _ZAP._defaultoptions.base_domain + getConfig('endpoint') + API_VERSIONS[path] + '/'; // no i18n
195
+ var org = PATHS_WITHOUT_ORG[path] ? '' : _ZAP._defaultoptions.zsoid + '/' + _ZAP._defaultoptions.projectID + '/'; // no i18n
196
+ // the debug twin sits under the same version, as debug/engagement/add next to engagement/add
197
+ var leaf = (usesDebugApi(path) ? 'debug/' : '') + DEFAULT_API_PATHS[path]; // no i18n
198
+ var url = base + org + leaf + getParameters(path);
199
+ if (!extra) {
200
+ return url;
201
+ }
202
+ var joiner = url.indexOf('?') === -1 ? '?' : '&'; // no i18n
203
+ Object.keys(extra).forEach(function (key) {
204
+ if (extra[key] === undefined || extra[key] === null || extra[key] === '') { // no i18n
205
+ return;
206
+ }
207
+ url += joiner + key + '=' + encodeURIComponent(String(extra[key]));
208
+ joiner = '&'; // no i18n
209
+ });
210
+ return url;
211
+ }
212
+ /**
213
+ * Says where a debug request can be traced. The answer carries a request id and a link into the
214
+ * server's own logs, which is the whole reason for calling the debug twin — printing it is what
215
+ * makes it reachable.
216
+ */
217
+ function reportDebugTrace(label, result) {
218
+ var data = result.data;
219
+ if (!data || isEmpty(data.req_id)) {
220
+ return;
221
+ }
222
+ Console.log(label + ': req_id ' + String(data.req_id)
223
+ + (isEmpty(data.path) ? '' : ', path ' + String(data.path))
224
+ + (isEmpty(data.producerLogsUrl) ? '' : ', logs ' + String(data.producerLogsUrl))); // no i18n
225
+ }
226
+ /** Whether this path should go to its debug twin. */
227
+ function usesDebugApi(path) {
228
+ // debugEnabled(), not the raw flag: an expired debug session is off even though init() asked
229
+ // for it, and an expired session must stop reaching the twin
230
+ return debugEnabled() && DEBUG_CAPABLE_PATHS[path] === true; // no i18n
231
+ }
232
+ /**
233
+ * Headers for every call made after device registration.
234
+ *
235
+ * apid and mapid are the only two, because they are the only two every url allows: the v2
236
+ * endpoints declare Access-Control-Allow-Headers as exactly "apid,mapid", and a browser drops
237
+ * any header outside that list at the preflight. Asking for the debug twin is done with the url
238
+ * alone, which needs no permission to send.
239
+ */
240
+ function apiHeaders() {
241
+ return { apid: getHeaderParams('apid'), mapid: getHeaderParams('mapid') }; // no i18n
242
+ }
243
+ /**
244
+ * Refusals that mean the payload itself is wrong. Sending it again cannot help, however many
245
+ * times it is tried — the proxy raises these before the server ever sees the body
246
+ * (JProxyExcepHandler: PATTERN_NOT_MATCHED and EXTRA_PARAM_FOUND share one message).
247
+ */
248
+ const PERMANENT_REFUSALS = {
249
+ PATTERN_NOT_MATCHED: true, // no i18n
250
+ EXTRA_PARAM_FOUND: true, // no i18n
251
+ INVALID_INPUTSTREAM: true, // no i18n
252
+ INVALID_PARAM: true, // no i18n
253
+ };
254
+ /**
255
+ * Whether a rejection is the server saying "never": the batch is malformed and keeping it would
256
+ * block every later batch behind it, for good. Anything else — a 5xx, a timeout, no network — is
257
+ * worth retrying and must not be treated this way.
258
+ */
259
+ function isPermanentRefusal(err) {
260
+ var result = err ? err.serverResult : undefined;
261
+ var code = result ? result.error_code : undefined;
262
+ return !isEmpty(code) && PERMANENT_REFUSALS[String(code)] === true;
263
+ }
264
+ /** The reason a response gives, preferring its error_code over the bare "failure". */
265
+ function refusalOf(label, result, raw) {
266
+ var reason = result && !isEmpty(result.error_code) ? String(result.error_code)
267
+ : (result ? String(result.result) : String(raw));
268
+ var err = new Error(label + ': ' + reason);
269
+ if (result) {
270
+ err.serverResult = result;
271
+ }
272
+ return err;
273
+ }
274
+ /**
275
+ * What an answer means: the parsed result when it reports success, otherwise a rejection that
276
+ * carries the server's own answer. Success also resets the path's attempt counter.
277
+ */
278
+ function settle(path, label, response) {
279
+ var _result = JSON.parse(response);
280
+ if (isSuccess(_result)) {
281
+ attemptSucceeded(path);
282
+ reportDebugTrace(label, _result);
283
+ return Promise.resolve(_result);
284
+ }
285
+ var refused = refusalOf(label, _result, response);
286
+ return Promise.reject(refused);
287
+ }
288
+ /**
289
+ * Sends one request. Resolves with the parsed response when it reports success; otherwise
290
+ * rejects with an Error carrying the server's answer. Requests are independent of each other:
291
+ * nothing orders one behind another.
292
+ */
293
+ function postToApptics(path, payload, headers, label, extra) {
294
+ var url = getUrlWithParams(path, Object.assign(beginAttempt(path), {}));
295
+ return makeRequest(url, getConfig('method'), payload, headers).then(function (response) {
296
+ return settle(path, label, response);
297
+ }, function (err) {
298
+ return Promise.reject(label + ': ' + err); // no i18n
299
+ });
300
+ }
301
+ /**
302
+ * The most a page may have in flight as keepalive bodies at once. Browsers refuse a keepalive
303
+ * request once the bodies still in flight would pass 64 KiB; this stays under that with room for
304
+ * the url and headers.
305
+ */
306
+ const KEEPALIVE_BUDGET = 60 * 1024;
307
+ /** Bytes of keepalive bodies sent and not yet answered. */
308
+ var keepaliveInFlight = 0;
309
+ function byteLength(payload) {
310
+ if (payload === null || payload === undefined) {
311
+ return 0;
312
+ }
313
+ if (typeof payload === 'string') { // no i18n
314
+ return typeof TextEncoder === 'function' ? new TextEncoder().encode(payload).length : payload.length * 3; // no i18n
315
+ }
316
+ var sized = payload;
317
+ return Number(sized.size || sized.byteLength || 0);
318
+ }
319
+ /**
320
+ * Sends as the page goes away, where a normal XHR would be cancelled with the document.
321
+ *
322
+ * `keepalive` is what lets the request outlive the page. fetch is used rather than sendBeacon
323
+ * because sendBeacon cannot carry the apid and mapid headers these urls require.
324
+ *
325
+ * The request leaves before this returns, so a caller never has to wait on it to send the next
326
+ * thing. The promise settles when the answer arrives, if the page is still there to see it: a
327
+ * caller removes what it sent only then. Data whose answer never comes stays stored and goes
328
+ * again on the next visit as attempt 2, which `attempt` and `firstattempttime` let the server
329
+ * recognise as a copy rather than store twice.
330
+ *
331
+ * A body that would take the page past the keepalive budget is not sent at all: the browser would
332
+ * refuse it, and it is better kept for the next visit than lost.
333
+ */
334
+ function postKeepalive(path, payload, headers, label, extra) {
335
+ var size = byteLength(payload);
336
+ if (typeof fetch === 'function' && keepaliveInFlight + size > KEEPALIVE_BUDGET) { // no i18n
337
+ Console.log(label + ': ' + size + ' bytes is over the keepalive budget, kept for the next send'); // no i18n
338
+ return Promise.reject(label + ': too large to send while the page closes'); // no i18n
339
+ }
340
+ var url = getUrlWithParams(path, Object.assign(beginAttempt(path), {}));
341
+ if (typeof fetch === 'function') { // no i18n
342
+ var answer;
343
+ try {
344
+ answer = fetch(url, {
345
+ method: getConfig('method'),
346
+ headers: Object.assign({ 'content-type': 'text/plain' }, headers), // no i18n
347
+ body: payload,
348
+ keepalive: true,
349
+ credentials: 'omit', // no i18n
350
+ });
351
+ }
352
+ catch (err) {
353
+ return Promise.reject(label + ': keepalive send not accepted: ' + String(err)); // no i18n
354
+ }
355
+ keepaliveInFlight += size;
356
+ var release = function () {
357
+ keepaliveInFlight = Math.max(0, keepaliveInFlight - size);
358
+ };
359
+ return answer.then(function (response) {
360
+ release();
361
+ if (!response || response.ok !== true) {
362
+ var status = response ? String(response.status) : ''; // no i18n
363
+ return Promise.reject(label + ': ' + status); // no i18n
364
+ }
365
+ var read = typeof response.text === 'function' ? response.text() : Promise.resolve(''); // no i18n
366
+ return read.then(function (text) {
367
+ // an ok answer with no readable body is taken at its status
368
+ if (isEmpty(text)) {
369
+ return settle(path, label, JSON.stringify({ result: 'success' })); // no i18n
370
+ }
371
+ return settle(path, label, text);
372
+ });
373
+ }, function (err) {
374
+ release();
375
+ return Promise.reject(label + ': ' + String(err)); // no i18n
376
+ });
377
+ }
378
+ // no fetch at all: a normal request, which the browser may cancel as the page goes away
379
+ return makeRequest(url, getConfig('method'), payload, headers).then(function (response) {
380
+ return settle(path, label, response);
381
+ }, function (err) {
382
+ return Promise.reject(label + ': ' + err); // no i18n
383
+ });
384
+ }
385
+ /** A labelled rejection for crawlers (the SDK does nothing for them), otherwise null. */
386
+ function rejectIfDisabled(label) {
387
+ return is_apptics_disabled() ? Promise.reject(label + ': apptics is disabled for this client') : null; // no i18n
388
+ }
389
+ /** A labelled rejection when the browser is offline, otherwise null. */
390
+ function rejectIfOffline(label) {
391
+ if (navigator.onLine == false) {
392
+ Console.warn(label + ': No Network'); // no i18n
393
+ return Promise.reject(label + ': No Network'); // no i18n
394
+ }
395
+ return null;
396
+ }
397
+ /** Device ids sent alongside every payload. */
398
+ function getMetaObj() {
399
+ return {
400
+ frameworkid: _ZAP._device_info.frameworkid || getKeyFromDeviceInfo('frameworkid'), // no i18n
401
+ aaid: _ZAP._device_info.aaid || getKeyFromDeviceInfo('aaid'), // no i18n
402
+ apid: _ZAP._device_info.apid || getKeyFromDeviceInfo('apid'), // no i18n
403
+ appversionid: _ZAP._device_info.appversionid || getKeyFromDeviceInfo('appversionid'), // no i18n
404
+ modelid: _ZAP._device_info.modelid || getKeyFromDeviceInfo('modelid'), // no i18n
405
+ appreleaseversionid: _ZAP._device_info.appreleaseversionid || getKeyFromDeviceInfo('appreleaseversionid'), // no i18n
406
+ osversionid: _ZAP._device_info.osversionid || getKeyFromDeviceInfo('osversionid'), // no i18n
407
+ timezoneid: _ZAP._device_info.timezoneid || getKeyFromDeviceInfo('timezoneid'), // no i18n
408
+ platformid: _ZAP._device_info.platformid || getKeyFromDeviceInfo('platformid'), // no i18n
409
+ devicetypeid: _ZAP._device_info.devicetypeid || getKeyFromDeviceInfo('devicetypeid') // no i18n
410
+ };
411
+ }
412
+ /**
413
+ * Calls made after registration need apid/mapid. Without them this asks device.ts to
414
+ * refresh device info (which registers) and returns a labelled rejection; otherwise null. Shared by sender, user
415
+ * and feedback (P11).
416
+ */
417
+ function rejectIfNoDeviceIds(label) {
418
+ if (isEmpty(getHeaderParams('apid')) && isEmpty(getHeaderParams('mapid'))) { // no i18n
419
+ hooks.refreshDeviceInfo();
420
+ return Promise.reject(label + ': You must call apptics.init() first'); // no i18n
421
+ }
422
+ return null;
423
+ }
424
+
425
+ export { KEEPALIVE_BUDGET, REQUEST_TIMEOUT_MS, apiHeaders, getHeaderParams, getMetaObj, getParameters, getUrlWithParams, isPermanentRefusal, makeRequest, postKeepalive, postToApptics, rejectIfDisabled, rejectIfNoDeviceIds, rejectIfOffline, usesDebugApi };
@@ -0,0 +1,26 @@
1
+ import type { Dict } from '../types.js';
2
+ /** Returned from an `each` iterator to stop iterating objects and array-likes. */
3
+ export declare const BREAKER: {};
4
+ /** Current time in epoch milliseconds, the unit of every SDK timestamp. */
5
+ export declare function nowMs(): number;
6
+ /** True when an Apptics API response reports success. */
7
+ export declare function isSuccess(result: unknown): boolean;
8
+ export declare function isEmpty(val: unknown): boolean;
9
+ export declare function isEmptyObj(obj: unknown): boolean;
10
+ export declare function objectsAreEqual(obj1: unknown, obj2: unknown): boolean;
11
+ export declare function compareTwoObjects(_newmap: Dict, _oldmap: Dict): boolean;
12
+ export declare function cloneMapExcludingKeys(originalObj: Dict, excludeKeys: readonly string[]): Dict;
13
+ /** Clones a JSON-compatible value. */
14
+ export declare function cloneObject<T>(obj: T): T;
15
+ /** Approximate size of a value in bytes (2 bytes per character). */
16
+ export declare function sizeof(obj: unknown): number;
17
+ /** True if `needle` occurs in the string or array. */
18
+ export declare function includes(haystack: {
19
+ indexOf(needle: any): number;
20
+ }, needle: unknown): boolean;
21
+ export declare function each(obj: any, iterator: (value: any, key: any, collection: any) => unknown, context?: unknown): void;
22
+ /**
23
+ * Generates a new distinct id (code lifted from apptics js).
24
+ * Busy-waits until Date.now() ticks.
25
+ */
26
+ export declare function getNewUUID(): string;
@@ -0,0 +1,161 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { AP_CONSTANTS } from './constants.js';
3
+
4
+ /** Returned from an `each` iterator to stop iterating objects and array-likes. */
5
+ const BREAKER = {};
6
+ /** Current time in epoch milliseconds, the unit of every SDK timestamp. */
7
+ function nowMs() {
8
+ return Math.round(new Date().getTime());
9
+ }
10
+ /** True when an Apptics API response reports success. */
11
+ function isSuccess(result) {
12
+ return !!result && typeof result === 'object' && result.result == AP_CONSTANTS.SUCCESS;
13
+ }
14
+ function isEmpty(val) {
15
+ // Check if val is empty
16
+ return val === undefined || val === null || val === ''; // no i18n
17
+ }
18
+ function isEmptyObj(obj) {
19
+ return !!obj && typeof obj === 'object' && Object.keys(obj).length === 0 && obj.constructor === Object;
20
+ }
21
+ function objectsAreEqual(obj1, obj2) {
22
+ // Compare the objects' properties
23
+ return JSON.stringify(obj1) === JSON.stringify(obj2);
24
+ }
25
+ function compareTwoObjects(_newmap, _oldmap) {
26
+ // Check if the number of keys is the same.
27
+ if (Object.keys(_newmap).length !== Object.keys(_oldmap).length) {
28
+ return false;
29
+ }
30
+ // Check if keys are the same
31
+ for (let key in _newmap) {
32
+ if (!_oldmap.hasOwnProperty(key)) {
33
+ return false;
34
+ }
35
+ }
36
+ // Check if objects associated with each key are the same
37
+ for (let key in _newmap) {
38
+ if (!objectsAreEqual(_newmap[key], _oldmap[key])) {
39
+ return false;
40
+ }
41
+ }
42
+ // Hash maps have the same keys and objects
43
+ return true;
44
+ }
45
+ function cloneMapExcludingKeys(originalObj, excludeKeys) {
46
+ const clonedObj = {};
47
+ for (let key in originalObj) {
48
+ if (!excludeKeys.includes(key)) {
49
+ clonedObj[key] = originalObj[key];
50
+ }
51
+ }
52
+ return clonedObj;
53
+ }
54
+ /** Clones a JSON-compatible value. */
55
+ function cloneObject(obj) {
56
+ return JSON.parse(JSON.stringify(obj));
57
+ }
58
+ /** Approximate size of a value in bytes (2 bytes per character). */
59
+ function sizeof(obj) {
60
+ let bytes = 0;
61
+ function sizeOf(value) {
62
+ if (value !== null && typeof value === 'object') { // no i18n
63
+ for (const key in value) {
64
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
65
+ bytes += key.length * 2; // 2 bytes per character
66
+ sizeOf(value[key]);
67
+ }
68
+ }
69
+ }
70
+ else if (typeof value === 'string') { // no i18n
71
+ bytes += value.length * 2; // 2 bytes per character
72
+ }
73
+ else if (typeof value === 'number') { // no i18n
74
+ bytes += 8; // 8 bytes for a number
75
+ }
76
+ else if (typeof value === 'boolean') { // no i18n
77
+ bytes += 4; // 4 bytes for a boolean
78
+ }
79
+ }
80
+ sizeOf(obj);
81
+ return bytes;
82
+ }
83
+ /** True if `needle` occurs in the string or array. */
84
+ function includes(haystack, needle) {
85
+ return haystack.indexOf(needle) !== -1;
86
+ }
87
+ function each(obj, iterator, context) {
88
+ if (obj === null || obj === undefined) {
89
+ return;
90
+ }
91
+ if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) {
92
+ obj.forEach(iterator, context);
93
+ }
94
+ else if (obj.length === +obj.length) {
95
+ for (var i = 0, l = obj.length; i < l; i++) {
96
+ if (i in obj && iterator.call(context, obj[i], i, obj) === BREAKER) {
97
+ return;
98
+ }
99
+ }
100
+ }
101
+ else {
102
+ for (var key in obj) {
103
+ if (Object.prototype.hasOwnProperty.call(obj, key)) {
104
+ if (iterator.call(context, obj[key], key, obj) === BREAKER) {
105
+ return;
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ /**
112
+ * Generates a new distinct id (code lifted from apptics js).
113
+ * Busy-waits until Date.now() ticks.
114
+ */
115
+ function getNewUUID() {
116
+ // Time/ticks information
117
+ var T = function () {
118
+ var d = Date.now(), i = 0;
119
+ // this while loop figures how many browser ticks go by
120
+ // before Date.now() returns a new number, ie the amount
121
+ // of ticks that go by per millisecond
122
+ while (d == Date.now()) {
123
+ i++;
124
+ }
125
+ return d.toString(16) + i.toString(16);
126
+ };
127
+ // Math.Random entropy
128
+ var R = function () {
129
+ return Math.random().toString(16).replace('.', ''); // no i18n
130
+ };
131
+ // User agent entropy
132
+ // This function takes the user agent string, and then xors
133
+ // together each sequence of 8 bytes. This produces a final
134
+ // sequence of 8 bytes which it returns as hex.
135
+ var UA = function () {
136
+ var ua = navigator.userAgent, i, ch, buffer = [], ret = 0;
137
+ function xor(result, byte_array) {
138
+ var j, tmp = 0;
139
+ for (j = 0; j < byte_array.length; j++) {
140
+ tmp |= buffer[j] << (j * 8);
141
+ }
142
+ return result ^ tmp;
143
+ }
144
+ for (i = 0; i < ua.length; i++) {
145
+ ch = ua.charCodeAt(i);
146
+ buffer.unshift(ch & 0xff);
147
+ if (buffer.length >= 4) {
148
+ ret = xor(ret, buffer);
149
+ buffer = [];
150
+ }
151
+ }
152
+ if (buffer.length > 0) {
153
+ ret = xor(ret, buffer);
154
+ }
155
+ return ret.toString(16);
156
+ };
157
+ var se = (screen.height * screen.width).toString(16);
158
+ return T() + '-' + R() + '-' + UA() + '-' + se + '-' + T(); // no i18n
159
+ }
160
+
161
+ export { BREAKER, cloneMapExcludingKeys, cloneObject, compareTwoObjects, each, getNewUUID, includes, isEmpty, isEmptyObj, isSuccess, nowMs, objectsAreEqual, sizeof };
@@ -0,0 +1,18 @@
1
+ import type { Dict, Properties, UserValidationResult } from '../types.js';
2
+ export declare function validateEventOrGroup(str: string | null | undefined): boolean;
3
+ /**
4
+ * Event, screen and error properties as the payload carries them: `{ data, datatype, isvalid }`.
5
+ *
6
+ * Each property is judged on its own, as on Android: a bad key (wrong characters, too long, the
7
+ * reserved ap_ prefix) or a value over 250 characters drops that property, and the rest are kept
8
+ * and the event is still logged. Past 24 properties, or 7,666 characters in all, the later ones are
9
+ * dropped. When nothing valid is left the result says why, in the shape the server has always taken
10
+ * for a refused set: `{ isvalid: false, message: { code, keys, valuekeys } }`.
11
+ */
12
+ export declare function validateJSON(jsonObj: Properties | Dict | null | undefined): Dict;
13
+ /** user/register accepts at most 10000 characters of body (max-len on its inputstream). */
14
+ export declare const USER_PROPERTIES_MAX_LENGTH = 10000;
15
+ /** user/register accepts at most this many user properties. */
16
+ export declare const USER_PROPERTIES_MAX_COUNT = 45;
17
+ export declare function userValidateJSON(obj: Dict): UserValidationResult;
18
+ export declare function validateScreenName(str: string | null | undefined): boolean;