@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,183 @@
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('../core/constants.js');
5
+ var state = require('../core/state.js');
6
+ var logger = require('../core/logger.js');
7
+ var utils = require('../core/utils.js');
8
+ var storage = require('../core/storage.js');
9
+ var consent = require('../core/consent.js');
10
+ var transport = require('../core/transport.js');
11
+ var validate = require('../core/validate.js');
12
+ var hooks = require('../core/hooks.js');
13
+
14
+ function getUser() {
15
+ return state._ZAP._user_info || {}; // no i18n
16
+ }
17
+ /**
18
+ * user/register wants properties as the validated triple — the values, their types, and what
19
+ * was rejected — which is what UserBuilder.build() returns. A plain object passed to setUser
20
+ * is validated here, so both forms go up in the same shape.
21
+ */
22
+ function asUserProperties(jsonObj) {
23
+ var maybeBuilt = jsonObj;
24
+ var built = maybeBuilt && typeof maybeBuilt === 'object' && maybeBuilt.data && maybeBuilt.datatype // no i18n
25
+ ? maybeBuilt
26
+ : validate.userValidateJSON(jsonObj);
27
+ built.message.forEach(function (problem) {
28
+ logger.logFailure(constants.AP_LOG_MODULE.PROPERTIES, 'AppticsUser.setUser: dropped ' + problem.keys.join(', ') + ' (error ' + problem.code + ')'); // no i18n
29
+ });
30
+ return built;
31
+ }
32
+ function setUser(userid, groupid, jsonObj) {
33
+ let _jsonObj = jsonObj || {};
34
+ userid = userid || ''; // no i18n
35
+ groupid = groupid || ''; // no i18n
36
+ if (!consent.canTrack('setUser')) { // no i18n
37
+ return;
38
+ }
39
+ if (utils.isEmpty(userid)) {
40
+ logger.logFailure(constants.AP_LOG_MODULE.PROPERTIES, 'AppticsUser.setUser: Invalid userid'); // no i18n
41
+ return;
42
+ }
43
+ var user_info = {
44
+ mam: userid,
45
+ customergroupid: groupid,
46
+ appversionid: state._ZAP._device_info.appversionid || '', // no i18n
47
+ status: 1,
48
+ happendat: utils.nowMs()
49
+ };
50
+ if (!utils.isEmptyObj(_jsonObj)) { // no i18n
51
+ user_info.userproperties = asUserProperties(_jsonObj);
52
+ }
53
+ registerUserWithApptics(user_info).then(function (user_info) {
54
+ logger.Console.log('setUser: ' + JSON.stringify(user_info)); // no i18n
55
+ }).catch(function (err) {
56
+ logger.Console.log(err);
57
+ });
58
+ }
59
+ function addOrUpdateUser(user_info) {
60
+ user_info.status = 1;
61
+ var users = storage.user_defaults.item('users') || []; // no i18n
62
+ users = users.map((item) => ({ ...item, status: 0 }));
63
+ var index = users.findIndex((userobj) => userobj.userid === user_info.userid);
64
+ if (index !== -1) {
65
+ users[index] = { ...users[index], ...user_info };
66
+ }
67
+ else {
68
+ users.push(user_info);
69
+ }
70
+ storage.user_defaults.add('users', users); // no i18n
71
+ // the user setUser registered, on its own as well: what this browser is tracking as now
72
+ storage.user_defaults.add('user_info', users[index !== -1 ? index : users.length - 1]); // no i18n
73
+ }
74
+ function getUserInfo() {
75
+ var stored = storage.user_defaults.item('user_info'); // no i18n
76
+ if (stored && typeof stored === 'object' && !utils.isEmpty(stored.userid)) { // no i18n
77
+ state._ZAP._user_info = stored;
78
+ return;
79
+ }
80
+ // registered before user_info was kept: the active one of the users list
81
+ var users = storage.user_defaults.item('users') || []; // no i18n
82
+ var activeuser = {};
83
+ if (users.length > 0) {
84
+ activeuser = users.filter((item) => item.status === 1)[0] || {};
85
+ }
86
+ state._ZAP._user_info = activeuser;
87
+ }
88
+ // Function to register the user
89
+ function registerUserWithApptics(user_info) {
90
+ var label = 'registerUserWithApptics'; // no i18n
91
+ var blocked = transport.rejectIfDisabled(label) || transport.rejectIfOffline(label);
92
+ if (blocked) {
93
+ return blocked;
94
+ }
95
+ if (utils.isEmptyObj(user_info)) {
96
+ return Promise.reject(label + ': nothing to register'); // no i18n
97
+ }
98
+ var missing = transport.rejectIfNoDeviceIds(label);
99
+ if (missing) {
100
+ return missing;
101
+ }
102
+ var payload = JSON.stringify(utils.cloneMapExcludingKeys(user_info, ['userid', 'groupid', 'happendat'])); // no i18n
103
+ return transport.postToApptics('reguser', payload, transport.apiHeaders(), label).then(function (result) {
104
+ var data = result.data || {};
105
+ user_info.userid = data.userid;
106
+ user_info.groupid = data.customergroupid;
107
+ consent.setTrackingStatus(constants.AP_TRACKING_STATUS.USAGE_TRACKING_WITH_PII);
108
+ addOrUpdateUser(user_info);
109
+ getUserInfo();
110
+ // the user and their customer group are known now: remote config conditions on them re-apply
111
+ hooks.hooks.remoteConfigUserChanged();
112
+ return data;
113
+ });
114
+ }
115
+ /** Builds validated user properties for setUser. */
116
+ class UserBuilder {
117
+ setFirstName(first_name) { this.first_name = first_name; return this; }
118
+ setLastName(last_name) { this.last_name = last_name; return this; }
119
+ setCompanyName(company_name) { this.company_name = company_name; return this; }
120
+ setEmailAddress(email_address) { this.email_address = email_address; return this; }
121
+ setContactNumber(contact_number) { this.contact_number = contact_number; return this; }
122
+ setCountry(country) { this.country = country; return this; }
123
+ setRegion(region) { this.region = region; return this; }
124
+ setCity(city) { this.city = city; return this; }
125
+ setGeoLocation(geo_location) { this.geo_location = geo_location; return this; }
126
+ setGender(gender) { this.gender = gender; return this; }
127
+ setPlanType(plan_type) { this.plan_type = plan_type; return this; }
128
+ setTimezone(timezone) { this.timezone = timezone; return this; }
129
+ setLanguage(language) { this.language = language; return this; }
130
+ setEngagementScore(engagement_score) { this.engagement_score = engagement_score; return this; }
131
+ setDateOfBirth(date_of_birth) { this.date_of_birth = date_of_birth; return this; }
132
+ addStringProperty(key, value) {
133
+ if (typeof value === 'string') { // no i18n
134
+ this[key] = value;
135
+ }
136
+ return this;
137
+ }
138
+ addBooleanProperty(key, value) {
139
+ if (typeof value === 'boolean') { // no i18n
140
+ this[key] = value;
141
+ }
142
+ return this;
143
+ }
144
+ addNumberProperty(key, value) {
145
+ if (typeof value === 'number' && Number.isFinite(value)) { // no i18n
146
+ this[key] = value;
147
+ }
148
+ return this;
149
+ }
150
+ setCustomProperties(obj) {
151
+ if (typeof obj === 'object' && obj !== null) { // no i18n
152
+ for (const [key, value] of Object.entries(obj)) {
153
+ this[key] = value;
154
+ }
155
+ }
156
+ return this;
157
+ }
158
+ build() {
159
+ const user = {};
160
+ const knownFields = [
161
+ 'first_name', 'last_name', 'company_name', 'email_address', 'contact_number',
162
+ 'country', 'region', 'city', 'geo_location', 'gender', 'plan_type', 'timezone',
163
+ 'language', 'engagement_score', 'date_of_birth'
164
+ ]; // no i18n
165
+ knownFields.forEach((field) => {
166
+ if (this[field] !== undefined)
167
+ user[field] = this[field];
168
+ });
169
+ Object.entries(this).forEach(([key, value]) => {
170
+ if (knownFields.indexOf(key) === -1 && typeof value !== 'function') { // no i18n
171
+ user[key] = value;
172
+ }
173
+ });
174
+ return validate.userValidateJSON(user);
175
+ }
176
+ }
177
+
178
+ exports.UserBuilder = UserBuilder;
179
+ exports.addOrUpdateUser = addOrUpdateUser;
180
+ exports.getUser = getUser;
181
+ exports.getUserInfo = getUserInfo;
182
+ exports.registerUserWithApptics = registerUserWithApptics;
183
+ exports.setUser = setUser;
@@ -0,0 +1,8 @@
1
+ import type { AppticsSdk } from './types.js';
2
+ /** Calls Apptics.init() when the page has the console snippet (window.appticssettings) and it hasn't run. */
3
+ export declare function autoInit(api: AppticsSdk['Apptics']): boolean;
4
+ /**
5
+ * Queues autoInit so an app that sets window.appticssettings and calls init() in its
6
+ * top-level code runs first (autoInit then sees init() already ran).
7
+ */
8
+ export declare function scheduleAutoInit(api: AppticsSdk['Apptics']): void;
@@ -0,0 +1,29 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { _ZAP } from './core/state.js';
3
+ import { getSnippetOptions } from './core/env.js';
4
+
5
+ /** Calls Apptics.init() when the page has the console snippet (window.appticssettings) and it hasn't run. */
6
+ function autoInit(api) {
7
+ if (_ZAP._initialised) {
8
+ return false;
9
+ }
10
+ var opts = getSnippetOptions();
11
+ if (!opts || typeof opts !== 'object') { // no i18n
12
+ return false;
13
+ }
14
+ return api.init(opts);
15
+ }
16
+ /**
17
+ * Queues autoInit so an app that sets window.appticssettings and calls init() in its
18
+ * top-level code runs first (autoInit then sees init() already ran).
19
+ */
20
+ function scheduleAutoInit(api) {
21
+ if (typeof window === 'undefined') { // no i18n
22
+ return;
23
+ }
24
+ queueMicrotask(function () {
25
+ autoInit(api);
26
+ });
27
+ }
28
+
29
+ export { autoInit, scheduleAutoInit };
@@ -0,0 +1,28 @@
1
+ import type { Dict } from '../types.js';
2
+ /** The largest value `attempt` may carry, from its own regex. */
3
+ export declare const MAX_ATTEMPTS = 5;
4
+ /**
5
+ * Whether this path has already used its five attempts, so the batch should be dropped rather
6
+ * than sent a sixth time with a param the proxy will refuse.
7
+ */
8
+ export declare function attemptsExhausted(path: string): boolean;
9
+ /**
10
+ * Records that a send is going out, and returns the params to put on it.
11
+ *
12
+ * Call it once per request, immediately before sending: it is what moves the attempt counter on,
13
+ * so calling it twice for one request would skip a number and reach five early.
14
+ */
15
+ export declare function beginAttempt(path: string): Dict;
16
+ /**
17
+ * Records that a send was accepted: the counter goes back to 1 and `lst` moves to now.
18
+ *
19
+ * For a page-close send the confirmation arrives after the caller has moved on, which is fine —
20
+ * nothing waits for this, it only decides what the *next* send says about itself.
21
+ */
22
+ export declare function attemptSucceeded(path: string): void;
23
+ /** Gives up on the current run of attempts, so the next send starts again at 1. */
24
+ export declare function resetAttempts(path: string): void;
25
+ /** When this path last had a send accepted, or 0. */
26
+ export declare function lastSendTime(path: string): number;
27
+ /** Forgets every path's bookkeeping. reset() calls it. */
28
+ export declare function clearAttempts(): void;
@@ -0,0 +1,106 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { RETRY_CAPABLE_PATHS } from './constants.js';
3
+ import { user_defaults } from './storage.js';
4
+ import { nowMs } from './utils.js';
5
+
6
+ /**
7
+ * Retry bookkeeping: `attempt`, `firstattempttime` and `lst`.
8
+ *
9
+ * Every url that carries data declares all three; app/addversion and getsdkconfig declare none,
10
+ * because they are start-up calls whose answers the SDK needs rather than payloads it is pushing.
11
+ *
12
+ * What they are for is the case this SDK cannot see on its own. A send goes out, the server
13
+ * stores it, and the answer is lost on the way back — a closed tab, a dropped connection, a
14
+ * proxy that times out. The SDK has no way to tell that from a send that never arrived, so it
15
+ * sends again. `attempt` and `firstattempttime` are what let the server recognise the second
16
+ * copy as the same payload rather than storing it twice. Without them, every retry is a
17
+ * duplicate session.
18
+ *
19
+ * `attempt` is declared `regex="[1-5]"`, so five is not a policy choice here — it is the largest
20
+ * number the proxy will accept. A batch that has not landed in five passes is dropped, because
21
+ * the sixth would be refused for the param rather than for the payload, which would look like a
22
+ * different fault entirely.
23
+ *
24
+ * State is per path and survives a reload, which is the point: the tab that was closed mid-send
25
+ * is exactly the one that needs to say "attempt 2" when it comes back.
26
+ */
27
+ /** The largest value `attempt` may carry, from its own regex. */
28
+ const MAX_ATTEMPTS = 5;
29
+ const STORE_KEY = 'sendstate'; // no i18n
30
+ function allState() {
31
+ var saved = user_defaults.item(STORE_KEY);
32
+ return saved && typeof saved === 'object' ? saved : {};
33
+ }
34
+ function stateOf(path) {
35
+ var state = allState()[path];
36
+ return state && typeof state === 'object'
37
+ ? { attempt: Number(state.attempt) || 1, firstattempttime: Number(state.firstattempttime) || 0, lst: Number(state.lst) || 0 }
38
+ : { attempt: 1, firstattempttime: 0, lst: 0 };
39
+ }
40
+ function save(path, state) {
41
+ var all = allState();
42
+ all[path] = state;
43
+ user_defaults.add(STORE_KEY, all);
44
+ }
45
+ /**
46
+ * Whether this path has already used its five attempts, so the batch should be dropped rather
47
+ * than sent a sixth time with a param the proxy will refuse.
48
+ */
49
+ function attemptsExhausted(path) {
50
+ return stateOf(path).attempt > MAX_ATTEMPTS;
51
+ }
52
+ /**
53
+ * Records that a send is going out, and returns the params to put on it.
54
+ *
55
+ * Call it once per request, immediately before sending: it is what moves the attempt counter on,
56
+ * so calling it twice for one request would skip a number and reach five early.
57
+ */
58
+ function beginAttempt(path) {
59
+ if (!RETRY_CAPABLE_PATHS[path]) {
60
+ return {};
61
+ }
62
+ var state = stateOf(path);
63
+ var at = nowMs();
64
+ if (state.attempt <= 1 || state.firstattempttime === 0) {
65
+ state.attempt = 1;
66
+ state.firstattempttime = at;
67
+ }
68
+ var params = {
69
+ attempt: String(Math.min(state.attempt, MAX_ATTEMPTS)),
70
+ firstattempttime: state.firstattempttime,
71
+ };
72
+ // lst is the last send this path had accepted. There is none before the first one lands, and
73
+ // an optional param is better absent than present and meaningless
74
+ if (state.lst > 0) {
75
+ params.lst = state.lst; // no i18n
76
+ }
77
+ // the next send for this path is the next attempt, unless this one is confirmed first
78
+ save(path, { attempt: state.attempt + 1, firstattempttime: state.firstattempttime, lst: state.lst });
79
+ return params;
80
+ }
81
+ /**
82
+ * Records that a send was accepted: the counter goes back to 1 and `lst` moves to now.
83
+ *
84
+ * For a page-close send the confirmation arrives after the caller has moved on, which is fine —
85
+ * nothing waits for this, it only decides what the *next* send says about itself.
86
+ */
87
+ function attemptSucceeded(path) {
88
+ if (!RETRY_CAPABLE_PATHS[path]) {
89
+ return;
90
+ }
91
+ save(path, { attempt: 1, firstattempttime: 0, lst: nowMs() });
92
+ }
93
+ /** Gives up on the current run of attempts, so the next send starts again at 1. */
94
+ function resetAttempts(path) {
95
+ if (!RETRY_CAPABLE_PATHS[path]) {
96
+ return;
97
+ }
98
+ var state = stateOf(path);
99
+ save(path, { attempt: 1, firstattempttime: 0, lst: state.lst });
100
+ }
101
+ /** Forgets every path's bookkeeping. reset() calls it. */
102
+ function clearAttempts() {
103
+ user_defaults.add(STORE_KEY, undefined);
104
+ }
105
+
106
+ export { MAX_ATTEMPTS, attemptSucceeded, attemptsExhausted, beginAttempt, clearAttempts, resetAttempts };
@@ -0,0 +1,32 @@
1
+ import { type Queue } from './storage.js';
2
+ import { type ApiPath } from './transport.js';
3
+ import type { Dict, QueueItem, ServerResult } from '../types.js';
4
+ /** Retries `send` in 500 ms, replacing any retry already scheduled. */
5
+ export declare function defer(send: () => Promise<void>): void;
6
+ export declare function clearDefer(): void;
7
+ /** Only one tab sends a queue at a time. Without the Web Locks API, runs directly (1.x behaviour). */
8
+ export declare function withSendLock(name: string, run: () => Promise<void>): Promise<void>;
9
+ /**
10
+ * The batch to send: closed items within batch_request_timeout days.
11
+ * Expired items are removed from the queue without being sent.
12
+ */
13
+ export declare function freshItems(queue: Queue, isClosed: (item: QueueItem) => boolean, timeOf: (item: QueueItem) => number): Promise<QueueItem[]>;
14
+ /**
15
+ * Sends one batch of queued items. Resolves only when the server has accepted it, so the caller
16
+ * removes the items then and not before: a batch that fails stays queued and goes again on the
17
+ * next pass, as attempt 2, which `attempt` and `firstattempttime` let the server recognise as a
18
+ * copy rather than store twice.
19
+ *
20
+ * With `forget` (the page is closing) it goes by keepalive, and the promise settles if the answer
21
+ * arrives before the page is gone. See postKeepalive.
22
+ *
23
+ * Five attempts is the cap, because `attempt` is declared regex="[1-5]" and a sixth would be
24
+ * refused for the param rather than for the payload.
25
+ */
26
+ export declare function sendBatch(path: ApiPath, label: string, _payload: Dict, forget?: boolean): Promise<ServerResult>;
27
+ /**
28
+ * Hands a send's outcome back to a sender. Normally the sender waits for it. While the page
29
+ * closes it does not: the request is already out, and waiting would hold the next queue's send
30
+ * until after the page has gone. The outcome is still handled whenever it arrives.
31
+ */
32
+ export declare function awaitUnlessClosing(landed: Promise<unknown>, forget: boolean | undefined, label: string): Promise<void> | undefined;
@@ -0,0 +1,109 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { _ZAP, isExpired } from './state.js';
3
+ import { Console, warnAlways } from './logger.js';
4
+ import { isEmptyObj, sizeof } from './utils.js';
5
+ import './constants.js';
6
+ import './db.js';
7
+ import { shouldTrackOrSendData } from './consent.js';
8
+ import { attemptsExhausted, MAX_ATTEMPTS, resetAttempts } from './attempts.js';
9
+ import { rejectIfDisabled, rejectIfNoDeviceIds, getMetaObj, postKeepalive, apiHeaders, postToApptics } from './transport.js';
10
+
11
+ /** Retries `send` in 500 ms, replacing any retry already scheduled. */
12
+ function defer(send) {
13
+ if (_ZAP._deferSendTimer) {
14
+ clearTimeout(_ZAP._deferSendTimer);
15
+ }
16
+ _ZAP._deferSendTimer = setTimeout(send, 500);
17
+ }
18
+ function clearDefer() {
19
+ if (_ZAP._deferSendTimer) {
20
+ clearTimeout(_ZAP._deferSendTimer);
21
+ _ZAP._deferSendTimer = null;
22
+ }
23
+ }
24
+ /** Only one tab sends a queue at a time. Without the Web Locks API, runs directly (1.x behaviour). */
25
+ function withSendLock(name, run) {
26
+ var locks = typeof navigator !== 'undefined' ? navigator.locks : undefined; // no i18n
27
+ if (!locks || typeof locks.request !== 'function') { // no i18n
28
+ return run();
29
+ }
30
+ return locks.request('apptics-send-' + name, { ifAvailable: true }, function (lock) {
31
+ return lock ? run() : undefined;
32
+ }).then(function () { return undefined; });
33
+ }
34
+ /**
35
+ * The batch to send: closed items within batch_request_timeout days.
36
+ * Expired items are removed from the queue without being sent.
37
+ */
38
+ function freshItems(queue, isClosed, timeOf) {
39
+ return queue.payload().then(function (items) {
40
+ var fresh = [];
41
+ var expired = [];
42
+ items.forEach(function (item) {
43
+ if (!isClosed(item)) {
44
+ return;
45
+ }
46
+ (isExpired(timeOf(item)) ? expired : fresh).push(item);
47
+ });
48
+ return expired.length ? queue.remove(expired).then(function () { return fresh; }) : fresh;
49
+ });
50
+ }
51
+ /**
52
+ * Sends one batch of queued items. Resolves only when the server has accepted it, so the caller
53
+ * removes the items then and not before: a batch that fails stays queued and goes again on the
54
+ * next pass, as attempt 2, which `attempt` and `firstattempttime` let the server recognise as a
55
+ * copy rather than store twice.
56
+ *
57
+ * With `forget` (the page is closing) it goes by keepalive, and the promise settles if the answer
58
+ * arrives before the page is gone. See postKeepalive.
59
+ *
60
+ * Five attempts is the cap, because `attempt` is declared regex="[1-5]" and a sixth would be
61
+ * refused for the param rather than for the payload.
62
+ */
63
+ function sendBatch(path, label, _payload, forget) {
64
+ var blocked = rejectIfDisabled(label);
65
+ if (blocked) {
66
+ return blocked;
67
+ }
68
+ if (!shouldTrackOrSendData()) {
69
+ return Promise.reject(label + ': tracking is off'); // no i18n
70
+ }
71
+ if (isEmptyObj(_payload)) {
72
+ return Promise.reject(label + ': nothing to send'); // no i18n
73
+ }
74
+ var missing = rejectIfNoDeviceIds(label);
75
+ if (missing) {
76
+ return missing;
77
+ }
78
+ if (!_payload.hasOwnProperty('meta')) { // no i18n
79
+ _payload.meta = getMetaObj();
80
+ }
81
+ if (attemptsExhausted(path)) {
82
+ // five passes without a confirmed landing. Keeping it would block every later batch
83
+ // behind a payload the proxy will now refuse for its attempt number alone
84
+ warnAlways('apptics: dropping a ' + label + ' batch after ' + MAX_ATTEMPTS + ' attempts'); // no i18n
85
+ resetAttempts(path);
86
+ return Promise.resolve({ result: 'success' }); // no i18n
87
+ }
88
+ Console.log(label + ': Payload size : ' + (sizeof(_payload) / 1024)); // no i18n
89
+ var body = JSON.stringify(_payload);
90
+ return forget
91
+ ? postKeepalive(path, body, apiHeaders(), label)
92
+ : postToApptics(path, body, apiHeaders(), label);
93
+ }
94
+ /**
95
+ * Hands a send's outcome back to a sender. Normally the sender waits for it. While the page
96
+ * closes it does not: the request is already out, and waiting would hold the next queue's send
97
+ * until after the page has gone. The outcome is still handled whenever it arrives.
98
+ */
99
+ function awaitUnlessClosing(landed, forget, label) {
100
+ if (!forget) {
101
+ return landed.then(function () { return undefined; });
102
+ }
103
+ landed.catch(function (err) {
104
+ Console.log(label + ': not confirmed before the page closed, kept for the next send: ' + String(err)); // no i18n
105
+ });
106
+ return undefined;
107
+ }
108
+
109
+ export { awaitUnlessClosing, clearDefer, defer, freshItems, sendBatch, withSendLock };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Where a log line was raised, for logSDK's `filename` and `linenumber`.
3
+ *
4
+ * There is no caller introspection in a browser, so the only way to answer "which line was this"
5
+ * is to throw an Error nobody catches and read its stack. That is cheap enough for a channel that
6
+ * only carries the SDK's own failures, but it is never on the app's path: everything here is
7
+ * wrapped so a stack we cannot parse costs a line its call site and nothing more.
8
+ */
9
+ export interface CallSite {
10
+ /** The script's basename, not its url: logSDK caps filename at 100 characters. */
11
+ filename: string;
12
+ /** 0 when the stack gave us nothing — see entryFor() for why it is still sent. */
13
+ linenumber: number;
14
+ /** The calling function's name, when the frame has one. Anonymous callers have none. */
15
+ fn?: string;
16
+ }
17
+ export declare const NO_CALL_SITE: CallSite;
18
+ /**
19
+ * A call typed in the browser's developer console: there is no file, line or function to report,
20
+ * only the console's own placeholder for its input, so the line says plainly that it came from
21
+ * nowhere in the app. file_name and the function field both accept `-`.
22
+ */
23
+ export declare const CONSOLE_CALL_SITE: CallSite;
24
+ /**
25
+ * The frame `skip` frames down a stack, counting only the ones that name a file — V8 heads its
26
+ * stacks with an `Error` line and Firefox does not, so counting raw lines would read a different
27
+ * frame in each browser.
28
+ */
29
+ export declare function callSiteFromStack(stack: string | undefined, skip: number): CallSite;
30
+ /**
31
+ * Where the caller `skip` levels above this call sits. `skip` is 0 for this function's own
32
+ * caller; each wrapper between that caller and the place worth reporting adds one.
33
+ */
34
+ export declare function callSite(skip: number): CallSite;
@@ -0,0 +1,110 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ /**
3
+ * Where a log line was raised, for logSDK's `filename` and `linenumber`.
4
+ *
5
+ * There is no caller introspection in a browser, so the only way to answer "which line was this"
6
+ * is to throw an Error nobody catches and read its stack. That is cheap enough for a channel that
7
+ * only carries the SDK's own failures, but it is never on the app's path: everything here is
8
+ * wrapped so a stack we cannot parse costs a line its call site and nothing more.
9
+ */
10
+ const NO_CALL_SITE = { filename: '', linenumber: 0, fn: '' };
11
+ /**
12
+ * A call typed in the browser's developer console: there is no file, line or function to report,
13
+ * only the console's own placeholder for its input, so the line says plainly that it came from
14
+ * nowhere in the app. file_name and the function field both accept `-`.
15
+ */
16
+ const CONSOLE_CALL_SITE = { filename: '-', linenumber: 0, fn: '-' };
17
+ /**
18
+ * The frame of code run from the developer console, in each browser:
19
+ * V8 (Chrome, Edge): ` at <anonymous>:1:15` (the file is <anonymous>)
20
+ * Firefox: `@debugger eval code:1:15`
21
+ * Safari: `global code` or `eval code`, with no location at all
22
+ * V8 names a string run through eval or new Function <anonymous> too; it is no file either.
23
+ */
24
+ const CONSOLE_FILE_V8 = '<anonymous>'; // no i18n
25
+ const CONSOLE_FIREFOX = /debugger eval code/; // no i18n
26
+ const CONSOLE_SAFARI = /^(global|eval) code(@|$)/; // no i18n
27
+ /** logSDK declares max-len="100" on filename. */
28
+ const FILENAME_MAX = 100;
29
+ /**
30
+ * The file and line out of one stack frame, in either shape a browser produces:
31
+ * V8: ` at doThing (https://host/app.js:12:34)`
32
+ * Firefox/Safari: `doThing@https://host/app.js:12:34`
33
+ * Both end in `:line:column`, which is the only part that is the same everywhere, so the match is
34
+ * anchored there and the column is read only so that it can be thrown away — without it the
35
+ * pattern would take the column for the line.
36
+ */
37
+ const FRAME = /([^\s(@]+):(\d+):(\d+)\)?$/;
38
+ /** `https://host/path/app.js?v=2` -> `app.js`. The url would not fit in 100 characters. */
39
+ function basename(url) {
40
+ var path = url.split(/[?#]/)[0] || url;
41
+ var parts = path.split('/');
42
+ return (parts[parts.length - 1] || path).slice(0, FILENAME_MAX);
43
+ }
44
+ /**
45
+ * The function a frame names, in either shape:
46
+ * V8: `at doThing (` — or `at async doThing (`
47
+ * Firefox/Safari: `doThing@`
48
+ * A frame without one (`at https://…` or `@https://…`) is an anonymous caller, and gets ''.
49
+ */
50
+ const FRAME_FN_V8 = /^at\s+(?:async\s+)?(.+?)\s+\(/;
51
+ const FRAME_FN_OTHER = /^([^@\s]+)@/;
52
+ function frameFunction(frame) {
53
+ var match = FRAME_FN_V8.exec(frame) || FRAME_FN_OTHER.exec(frame);
54
+ return match ? (match[1] || '') : ''; // no i18n
55
+ }
56
+ function parseFrame(line) {
57
+ var trimmed = line.trim();
58
+ var match = FRAME.exec(trimmed);
59
+ if (match === null) {
60
+ return null;
61
+ }
62
+ var line_no = Number(match[2]);
63
+ if (!isFinite(line_no)) {
64
+ return null;
65
+ }
66
+ return { filename: basename(match[1] || ''), linenumber: line_no, fn: frameFunction(trimmed) };
67
+ }
68
+ /**
69
+ * The frame `skip` frames down a stack, counting only the ones that name a file — V8 heads its
70
+ * stacks with an `Error` line and Firefox does not, so counting raw lines would read a different
71
+ * frame in each browser.
72
+ */
73
+ function callSiteFromStack(stack, skip) {
74
+ if (!stack) {
75
+ return NO_CALL_SITE;
76
+ }
77
+ var lines = stack.split('\n');
78
+ var seen = 0;
79
+ for (var i = 0; i < lines.length; i++) {
80
+ var raw = (lines[i] || '').trim(); // no i18n
81
+ var frame = parseFrame(raw);
82
+ if (frame === null) {
83
+ // Safari's console frame has no location, so it is never a frame parseFrame reads
84
+ if (seen === skip && CONSOLE_SAFARI.test(raw)) {
85
+ return CONSOLE_CALL_SITE;
86
+ }
87
+ continue;
88
+ }
89
+ if (seen++ < skip) {
90
+ continue;
91
+ }
92
+ return frame.filename === CONSOLE_FILE_V8 || CONSOLE_FIREFOX.test(raw) ? CONSOLE_CALL_SITE : frame;
93
+ }
94
+ return NO_CALL_SITE;
95
+ }
96
+ /**
97
+ * Where the caller `skip` levels above this call sits. `skip` is 0 for this function's own
98
+ * caller; each wrapper between that caller and the place worth reporting adds one.
99
+ */
100
+ function callSite(skip) {
101
+ try {
102
+ // +1 for this function's own frame, which is never the answer
103
+ return callSiteFromStack(new Error().stack, skip + 1);
104
+ }
105
+ catch (err) {
106
+ return NO_CALL_SITE;
107
+ }
108
+ }
109
+
110
+ export { CONSOLE_CALL_SITE, NO_CALL_SITE, callSite, callSiteFromStack };
@@ -0,0 +1,27 @@
1
+ import type { TrackingStatus } from '../types.js';
2
+ /**
3
+ * DNT counts only when not ignored; while it counts, tracking is NO_TRACKING (opt_in_status).
4
+ * Decided on every visit and never stored: storing it made one visit with DNT on look like the
5
+ * visitor's own choice, so tracking stayed off after DNT was turned off or ignore_do_not_track set.
6
+ */
7
+ export declare function hasDoNotTrackEnabled(): boolean;
8
+ export declare function opt_in_status(): TrackingStatus;
9
+ export declare function shouldTrackOrSendData(): boolean;
10
+ /**
11
+ * The guard every tracking call starts with: init() has run, the client isn't a crawler,
12
+ * and consent / server flags allow tracking.
13
+ */
14
+ export declare function canTrack(caller: string): boolean;
15
+ /** canTrack plus the server's `engagementtracking` flag from getupdates (events, screens, sessions, api calls). */
16
+ export declare function canTrackEngagement(caller: string): boolean;
17
+ /**
18
+ * canTrack plus the server's heatmap flag (getsdkconfig module 18).
19
+ *
20
+ * Heatmap rode the engagement flag until v2 gave it one of its own, which matters: an app may
21
+ * well want events while declining to have every click's coordinates recorded.
22
+ */
23
+ export declare function canTrackHeatmap(caller: string): boolean;
24
+ /** canTrack plus the server's `errortracking` flag from getupdates. */
25
+ export declare function canTrackErrors(caller: string): boolean;
26
+ export declare function setTrackingStatus(trackingState: TrackingStatus): void;
27
+ export declare function getTrackingStatus(): TrackingStatus;