@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,74 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { _ZAP, getConfig } from './core/state.js';
3
+ import { nowMs } from './core/utils.js';
4
+ import { Console } from './core/logger.js';
5
+ import { canTrack } from './core/consent.js';
6
+ import { clearDefer } from './core/batch.js';
7
+ import { sendEngagementData } from './engagement/send.js';
8
+ import { sendErrorData } from './errors/send.js';
9
+ import { hooks } from './core/hooks.js';
10
+ import { getUpdatesFromServer } from './device/index.js';
11
+ import { expireDebugIfIdle } from './core/debug.js';
12
+
13
+ /**
14
+ * Sends everything queued now. With `forget`, the requests are sent without waiting for a
15
+ * response (page hide), so they survive the page going away.
16
+ */
17
+ function flush(forget) {
18
+ if (!canTrack('flush')) { // no i18n
19
+ return Promise.resolve();
20
+ }
21
+ _ZAP._sending = false;
22
+ // one after the other: sending both at once makes the second wait for the 500 ms retry
23
+ return sendEngagementData(forget).then(function () {
24
+ return sendErrorData(forget);
25
+ }).then(function () {
26
+ // the hook heatmap/send.ts sets
27
+ return hooks.sendHeatmaps(forget);
28
+ });
29
+ }
30
+ var sendingInterval = null;
31
+ var getUpdatesInterval = null;
32
+ /** Starts the flush and getupdates intervals once; later calls do nothing until stopTimers(). */
33
+ function startTimers() {
34
+ if (sendingInterval === null) {
35
+ sendingInterval = setInterval(function () {
36
+ // the only tick that happens whether or not anything is being tracked, which is
37
+ // exactly the case debug mode has to expire in
38
+ expireDebugIfIdle();
39
+ Console.log('scheduleToSendDataToServer: Scheduling to send engagement data to the server after sometime'); // no i18n
40
+ // one after the other, as flush() does: run together, the second and third find the
41
+ // first still sending and are deferred, and the third's retry replaces the second's
42
+ sendEngagementData().then(function () {
43
+ return sendErrorData();
44
+ }).then(function () {
45
+ return hooks.sendHeatmaps();
46
+ });
47
+ }, getConfig('batch_flush_interval')); // no i18n
48
+ }
49
+ if (getUpdatesInterval === null) {
50
+ // the interval is the floor, not the schedule: getsdkconfig answers with next_check_after,
51
+ // and asking again before then is a call the server has already told us it will not answer
52
+ // differently. The timer still ticks so a server that sends no hint behaves as before.
53
+ getUpdatesInterval = setInterval(function () {
54
+ if (_ZAP._nextConfigCheck > 0 && nowMs() < _ZAP._nextConfigCheck) {
55
+ return;
56
+ }
57
+ Console.log('scheduleToGetUpdatesFromServer: asking the server for its config'); // no i18n
58
+ getUpdatesFromServer().catch(function (err) {
59
+ Console.log(err);
60
+ });
61
+ }, getConfig('getupdates_interval')); // no i18n
62
+ }
63
+ }
64
+ function stopTimers() {
65
+ if (sendingInterval !== null)
66
+ clearInterval(sendingInterval);
67
+ if (getUpdatesInterval !== null)
68
+ clearInterval(getUpdatesInterval);
69
+ sendingInterval = null;
70
+ getUpdatesInterval = null;
71
+ clearDefer();
72
+ }
73
+
74
+ export { flush, startTimers, stopTimers };
@@ -0,0 +1,385 @@
1
+ import type { AP_FEEDBACK_TYPE, AP_TRACKING_STATUS } from './core/constants.js';
2
+ import type { UserBuilder } from './user/index.js';
3
+ import type { ApiTrackingBuilder, ApiTrackingConfig } from './engagement/api-rules.js';
4
+ import type { DefinedEvent, DefinedEvents } from './engagement/defined-events.js';
5
+ /** One entry of screen_routes: a route pattern, or an exact path or a regular expression with the name to record. */
6
+ export type ScreenRoute = string | {
7
+ equals: string;
8
+ name: string;
9
+ } | {
10
+ regex: RegExp | string;
11
+ name: string;
12
+ };
13
+ /** Loose record for legacy payloads and server JSON that are built and sent as-is. */
14
+ export type Dict = Record<string, any>;
15
+ /** An item in the engagement or error queue. */
16
+ export interface QueueItem {
17
+ id?: string;
18
+ type?: string;
19
+ starttime?: number;
20
+ endtime?: number;
21
+ [key: string]: any;
22
+ }
23
+ /** Device properties sent to and returned by `device/add`. */
24
+ export type DeviceInfo = Dict;
25
+ export interface UserInfo {
26
+ userid?: string;
27
+ groupid?: string;
28
+ status?: number;
29
+ [key: string]: any;
30
+ }
31
+ export interface ServerResult<T = Dict> {
32
+ result: string;
33
+ data?: T;
34
+ error_code?: unknown;
35
+ [key: string]: any;
36
+ }
37
+ export type TrackingStatus = (typeof AP_TRACKING_STATUS)[keyof typeof AP_TRACKING_STATUS];
38
+ export type FeedbackType = (typeof AP_FEEDBACK_TYPE)[keyof typeof AP_FEEDBACK_TYPE];
39
+ export type Properties = Record<string, unknown>;
40
+ /** The config init() requires. The console snippet provides the same shape as window.appticssettings._defaultoptions. */
41
+ export interface AppticsConfig {
42
+ /** Apptics host every request goes to, e.g. https://apptics.zoho.com (a trailing slash is ignored). Was `serviceUrl`. */
43
+ base_url: string;
44
+ /** The app's key from the console, sent as the `zak` header on app/addversion and device registration. Was `zak`. */
45
+ auth_key: string;
46
+ /** The app's domain as registered in the console, e.g. com.zoho.web.zylker. Was `identifier`. */
47
+ app_domain: string;
48
+ /**
49
+ * Your app's version or build number, e.g. '2.4.0' or 512. Required: everything the SDK reports
50
+ * is only meaningful against the build it came from, so there is no default. Changing it
51
+ * registers the new version. Sent as text: a string is trimmed, and a number keeps only the
52
+ * digits JavaScript gives it (1.10 is '1.1'), so pass a dotted version as a string. A blank
53
+ * value, or a snippet placeholder such as 'YOUR_APP_VERSION', is refused.
54
+ */
55
+ appversion: string | number;
56
+ /** @deprecated ignored: app/addversion answers with the aaid */
57
+ aaid?: string;
58
+ /** @deprecated ignored: app/addversion answers with the aaid */
59
+ aaID?: string;
60
+ /** @deprecated ignored: app/addversion answers with the portal id */
61
+ zsoid?: string;
62
+ /** @deprecated ignored: app/addversion answers with the project id */
63
+ projectID?: string;
64
+ /** @deprecated 1.x console-snippet name for base_url: still read, with a warning */
65
+ base_domain?: string;
66
+ /** @deprecated 1.x console-snippet name for auth_key: still read, with a warning */
67
+ token?: string;
68
+ /**
69
+ * Debug mode: send engagement, exception and log payloads to their `debug/` twins, which answer
70
+ * with a request id and a link to the server's own logs, for following in the Apptics web
71
+ * console. Off by default; it does not change what is sent. Same as calling enableDebug().
72
+ */
73
+ debug?: boolean;
74
+ /** Log the SDK's own activity to the browser console. Off by default. */
75
+ console_log?: boolean;
76
+ ignore_do_not_track?: boolean;
77
+ /**
78
+ * Record the app's API calls automatically, by wrapping XHR and fetch. Off by default. The SDK's
79
+ * own requests are never recorded. Which hosts and endpoints are recorded, and under what path,
80
+ * is set with AppticsApi.configure(new AppticsApi.ApiTrackingBuilder()...build()).
81
+ */
82
+ track_api?: boolean;
83
+ /**
84
+ * Record screen views automatically: the page the SDK starts on, then every navigation —
85
+ * history.pushState / replaceState, back and forward, and `#/` hash routes. The screen is named
86
+ * by its path, without the query string. On by default. A inScreen() call within 300 ms of a
87
+ * navigation replaces its automatic view; set this false to track only the app's own calls.
88
+ */
89
+ track_screen?: boolean;
90
+ /**
91
+ * How automatic screen tracking names a path, tried in order; the first that matches wins, and a
92
+ * path none matches keeps its own name. Each entry is one of:
93
+ * - a route pattern, `'/users/{id}/orders'`: `{name}`, `:name` and `*` each match one segment,
94
+ * recorded as a star, so `/users/42/orders` and `/users/43/orders` are one screen;
95
+ * - `{ equals: '/', name: 'Home' }`: that path exactly;
96
+ * - `{ regex: /^\/orders\/\d+$/, name: 'Order detail' }`: any path the regular expression matches.
97
+ * Paths are matched without their query string.
98
+ */
99
+ screen_routes?: ScreenRoute[];
100
+ /**
101
+ * The feedback form's theme: 'light', 'dark', or 'auto' (the default) to follow the visitor's
102
+ * system setting. The colors are CSS variables on the form (`--zasdk-primary-color` and the rest
103
+ * of the `--zasdk-*` set), which a page may override.
104
+ */
105
+ feedback_theme?: 'light' | 'dark' | 'auto';
106
+ /** How often queued data is sent, in milliseconds. Default 30000, at least 1000. */
107
+ batch_flush_interval?: number;
108
+ /** How often the server's tracking flags are fetched, in milliseconds. Default 120000, at least 10000. */
109
+ getupdates_interval?: number;
110
+ /** Most items in one batch. Default 50, between 1 and 500. */
111
+ batch_size?: number;
112
+ /** Days an unsent item is kept before it is dropped. Default 7, between 1 and 30. */
113
+ batch_request_timeout?: number;
114
+ /** Idle minutes that end a session. Default 30, between 1 and 1440. */
115
+ inactiveduration?: number;
116
+ /**
117
+ * How long a visit must last before its session is recorded, in milliseconds. Default 5000, at
118
+ * most 60000. A shorter visit with nothing tracked in it is not reported at all; anything tracked
119
+ * inside the window records the session at once, with its real start time. 0 turns the wait off.
120
+ */
121
+ min_session_duration?: number;
122
+ /**
123
+ * Record where people click and how far they scroll. Off by default; AppticsHeatmap.trackHeatmap()
124
+ * switches it later.
125
+ */
126
+ track_heatmap?: boolean;
127
+ /** Most heatmap records one visit may produce. Default 500; capture pauses past it. */
128
+ heatmap_max_per_session?: number;
129
+ /** @deprecated the earlier name for `debug` (debug mode); `debug` wins when both are given */
130
+ debug_api?: boolean;
131
+ /**
132
+ * What to call this device in the debug stream, e.g. 'QA iPad 3'. Sent on engagement,
133
+ * exception and log, the three endpoints that declare it. Unset, nothing is sent unless
134
+ * debug mode is on, where a label is derived from the browser and OS instead.
135
+ */
136
+ device_name?: string;
137
+ [key: string]: unknown;
138
+ }
139
+ export interface UserValidationResult {
140
+ data: Record<string, string | number | boolean>;
141
+ datatype: Record<string, 'String' | 'Number' | 'Boolean'>;
142
+ message: Array<{
143
+ code: 101 | 102 | 103 | 104;
144
+ keys: string[];
145
+ }>;
146
+ }
147
+ /**
148
+ * Screen recording in the feedback form, as getsdkconfig's `quartz` block sets it up:
149
+ * { quartz_enabled, quartz_workspace, quartz_department, quartz_domain, quartz_cdn_url }
150
+ * The app passes none of it; the console's settings for the app decide.
151
+ */
152
+ export interface QuartzSettings {
153
+ enabled: boolean;
154
+ /** quartz_workspace: the workspace the recording is filed under. */
155
+ workspace: string;
156
+ /** quartz_department: the department within it. */
157
+ department: string;
158
+ /** quartz_domain, e.g. zoho.com: recordings go to https://quartz.<domain>. */
159
+ domain: string;
160
+ /**
161
+ * quartz_cdn_url: the Quartz script, loaded by the SDK when the form needs it. When the answer
162
+ * has none, the SDK uses Zoho's CDN for the serviceUrl (static.localzohocdn.com for localzoho,
163
+ * static.zohocdn.com otherwise).
164
+ */
165
+ cdnUrl: string;
166
+ }
167
+ export interface QuartzApi {
168
+ startRecording(details: {
169
+ workspaceLinkName: string;
170
+ departmentLinkName: string;
171
+ recordingDomain: string;
172
+ }): void;
173
+ previewVideo(): void;
174
+ editVideo(options: {
175
+ quartzBranding: boolean;
176
+ }): void;
177
+ clearFeedback(): void;
178
+ endRecording(): void;
179
+ setVideoContent(element: Element | null): void;
180
+ submitRecording(details: {
181
+ email: string;
182
+ subject: string;
183
+ }): Promise<{
184
+ feedbackLink?: string;
185
+ } | undefined>;
186
+ }
187
+ export interface QuartzConstantsApi {
188
+ ErrorType: Record<string, string>;
189
+ FeedbackState: Record<string, string>;
190
+ }
191
+ /**
192
+ * One heatmap record: a click or a finished scroll gesture, as `heatmap/add` takes it.
193
+ *
194
+ * Web-shaped. The endpoint's mobile fields have no meaning in a browser and are not sent:
195
+ * `battery_in`/`battery_out` (the Battery Status API is gone from Firefox and never existed in
196
+ * Safari), `pressure` and `finger_count` (0 and 1 for any mouse), `service_provider` (a carrier
197
+ * name, which the web has no access to). Sending constants for them would put dead columns in
198
+ * every record.
199
+ */
200
+ export interface HeatmapRecord {
201
+ /** Queue key; removed before the record is sent. */
202
+ id?: string;
203
+ session_start_time: number;
204
+ /** When this record happened. The only thing that orders records inside a session. */
205
+ triggered_time: number;
206
+ screen: string;
207
+ url_path: string;
208
+ /**
209
+ * 'buttonclick' for a click on something clickable, 'default' otherwise. The server accepts
210
+ * only `event|default|buttonclick`; the kind of movement goes in `gesture_type`.
211
+ */
212
+ triggered_type: 'event' | 'default' | 'buttonclick';
213
+ /** 'click', or 'up-scroll' / 'down-scroll' / 'left-scroll' / 'right-scroll'. */
214
+ gesture_type: string;
215
+ /** Milliseconds the gesture took. 0 for a click. */
216
+ gesture_duration: number;
217
+ /** 'mouse', 'touch' or 'pen' from the pointer event. Absent for a scroll, which has none. */
218
+ input_type?: string;
219
+ /** A name for the element: an author's attribute where there is one, its text only with PII consent. */
220
+ element_label: string;
221
+ /** A stable number for the element's position in the tree, so clicks on one control group together. */
222
+ triggered_id: number;
223
+ coordinate_x: number;
224
+ coordinate_y: number;
225
+ /** 0-1 across the viewport width. */
226
+ normalized_x: number;
227
+ /** 0-1 down the full page height, which is what a scroll-depth map reads. */
228
+ normalized_y: number;
229
+ scroll_offset_x: number;
230
+ scroll_offset_y: number;
231
+ screen_width: number;
232
+ screen_height: number;
233
+ content_height: number;
234
+ orientation: number;
235
+ network_status: number;
236
+ edge_type: string;
237
+ /** Pixels per second, x1000. 0 for a click. */
238
+ velocity: number;
239
+ is_clickable: 0 | 1;
240
+ is_rage_click: 0 | 1;
241
+ is_dead_click: 0 | 1;
242
+ }
243
+ /** What `AppticsError.trackError` accepts: a window `error` / `unhandledrejection` event or the same shape. */
244
+ export type ErrorLike = Event | {
245
+ type?: string;
246
+ error?: unknown;
247
+ reason?: unknown;
248
+ };
249
+ /** What sendFeedback() sends. Every key is optional. */
250
+ export interface SendFeedbackOptions {
251
+ /** AppticsFeedback.AP_FEEDBACK_TYPE: BUG (0), FEEDBACK (1, the default), HELP (2), REPORT (3). */
252
+ type?: FeedbackType;
253
+ /** The feedback's text. */
254
+ message?: string;
255
+ /** Files to attach: at most 5, 10 MB in all. */
256
+ attachments?: FileList | File[] | null;
257
+ /** Log files of the app's own to send along. */
258
+ logFiles?: FileList | File[] | null;
259
+ /** The addDiagnosticsInfo() entries and the device's details: unset sends them when there are entries waiting. */
260
+ includeDiagnostics?: boolean;
261
+ /** The addFeedbackLog() lines: unset sends them when there are any, false never does. */
262
+ includeLog?: boolean;
263
+ /** Sends it from nobody. Unset, it is from the active user AppticsUser.setUser registered. */
264
+ isAnonymous?: boolean;
265
+ }
266
+ /** What feedbackFormOpen() fills the form in with. Every key is optional. */
267
+ export interface FeedbackOpenOptions {
268
+ /** The tab the form opens on: AppticsFeedback.AP_FEEDBACK_TYPE.BUG, FEEDBACK, HELP or REPORT. */
269
+ type?: FeedbackType;
270
+ /** Text already in the description. */
271
+ message?: string;
272
+ /** Starts the logs toggle on. */
273
+ includeLog?: boolean;
274
+ /** Starts the diagnostics toggle on. */
275
+ includeDiagnostics?: boolean;
276
+ /** Files already attached: at most 5, 10 MB in all. */
277
+ attachments?: FileList | File[] | null;
278
+ /** Log files of the app's own already attached. */
279
+ logFiles?: FileList | File[] | null;
280
+ /** Starts the user picker on Anonymous, even with a user registered. */
281
+ isAnonymous?: boolean;
282
+ }
283
+ /** The optional feedback modal, from '@zoho_apptics/apptics-js-sdk/feedback'. */
284
+ export interface AppticsFeedbackApi {
285
+ /**
286
+ * Sends feedback without the form. Resolves once it is sent; rejects when it wasn't: the SDK
287
+ * has not started (no init()), the browser is offline, or the server refused it.
288
+ */
289
+ sendFeedback(options?: SendFeedbackOptions): Promise<void>;
290
+ /** Opens the form, filled in with `options` when they are given. */
291
+ feedbackFormOpen(options?: FeedbackOpenOptions): void;
292
+ feedbackFormClose(): void;
293
+ /** The feedback types: BUG, FEEDBACK, HELP, REPORT. */
294
+ AP_FEEDBACK_TYPE: typeof AP_FEEDBACK_TYPE;
295
+ /** Records a timestamped line, sent as feedbacklog.txt with the next feedback submission. */
296
+ addFeedbackLog(message: string): void;
297
+ /** Records a diagnostics key/value under `heading`, sent inside dyninfo.txt with the next feedback. */
298
+ addDiagnosticsInfo(heading: string, key: string, value: unknown): void;
299
+ /**
300
+ * The form's theme from now on, restyling one open now: 'light', 'dark', or 'auto' to follow
301
+ * the visitor's system setting. For a page with its own theme switch, called as it changes.
302
+ */
303
+ setFeedbackTheme(theme: 'light' | 'dark' | 'auto'): void;
304
+ }
305
+ export interface AppticsSdk {
306
+ /** Android's Apptics: starting the SDK, and what applies to all of it. */
307
+ Apptics: {
308
+ /** Starts the SDK. The config object is required; the console snippet supplies it via auto-init. */
309
+ init(config: AppticsConfig): boolean;
310
+ /** Resolves true once start-up (storage load, device, session) has finished; false if it can't start. */
311
+ ready(): Promise<boolean>;
312
+ /** Sends stored engagements, errors and heatmap records now; resolves once they have gone out. */
313
+ flush(): Promise<void>;
314
+ /** Clears stored identity, queued data and remote config values, then starts again. */
315
+ reset(): void;
316
+ /**
317
+ * Turns debug mode on, before or after Apptics.init(). Engagement, exception and log then go to
318
+ * their `debug/` twins, whose answers carry a request id and a link into the server's own logs. It
319
+ * switches itself off after an hour with nothing tracked.
320
+ */
321
+ enableDebug(): void;
322
+ /** Turns debug mode off, before or after Apptics.init(); wins over `debug` in init(). */
323
+ disableDebug(): void;
324
+ };
325
+ /** Android's AppticsEvents. */
326
+ AppticsEvent: {
327
+ /** Apptics' defined events, as Android's DefinedEvents, to log with addEvent. */
328
+ DefinedEvents: typeof DefinedEvents;
329
+ /** An event. An invalid name or group is not logged; a group left out is `default`. */
330
+ addEvent(eventName: string, groupName?: string, properties?: Properties): void;
331
+ /** A defined event (AppticsEvent.DefinedEvents.AP_USER_LOGIN, …), which brings its own group. */
332
+ addEvent(definedEvent: DefinedEvent, properties?: Properties): void;
333
+ };
334
+ /** Android's AppticsScreenTracker. */
335
+ AppticsScreen: {
336
+ /** Records a screen view and returns its id, for outScreen; '' for an invalid name. */
337
+ inScreen(screenName: string, properties?: Properties): string;
338
+ /** Ends the screen view inScreen began, before the next screen would. */
339
+ outScreen(id: string): void;
340
+ };
341
+ /** Android's AppticsApiTracker. */
342
+ AppticsApi: {
343
+ /** Builds the rules configure takes: `new AppticsApi.ApiTrackingBuilder()…build()`. */
344
+ ApiTrackingBuilder: typeof ApiTrackingBuilder;
345
+ /** Begins timing one call; returns the id endTrackApi takes. */
346
+ startTrackApi(url: string, method?: string): string;
347
+ /** Finishes the call startTrackApi began, and records it. */
348
+ endTrackApi(id: string, responseCode: number, responseMessage?: string): void;
349
+ /** The rules API tracking records by, from ApiTrackingBuilder. Works before Apptics.init(). */
350
+ configure(config: ApiTrackingConfig | ApiTrackingBuilder): void;
351
+ /**
352
+ * Turns automatic API tracking on or off after Apptics.init(). Equivalent to the `track_api`
353
+ * config flag, which is the usual way to set it.
354
+ */
355
+ enableApiTracking(enabled?: boolean): void;
356
+ };
357
+ /** Errors the app caught, and the switch for tracking uncaught ones. */
358
+ AppticsError: {
359
+ /** Reports an error the app caught, or an `error` / `unhandledrejection` event. */
360
+ trackError(error: ErrorLike, properties?: Properties): void;
361
+ /** Turns the automatic tracking of uncaught errors and unhandled rejections on or off. */
362
+ trackGlobalErrorHandler(enabled?: boolean): void;
363
+ };
364
+ /** Android's AppticsUser. */
365
+ AppticsUser: {
366
+ /** Registers the signed-in user. Properties may be a plain object, or the result of UserBuilder.build(). */
367
+ setUser(userid: string, groupid?: string, properties?: Properties | UserValidationResult): void;
368
+ /** The registered user, or {} when there is none. */
369
+ getUser(): UserInfo;
370
+ /** Builds the user's properties for setUser. */
371
+ UserBuilder: typeof UserBuilder;
372
+ };
373
+ /** Click and scroll capture for the console's heatmaps. */
374
+ AppticsHeatmap: {
375
+ /** Starts or stops recording clicks and scrolls; `on` defaults to true. */
376
+ trackHeatmap(on?: boolean): void;
377
+ };
378
+ /** Android's AppticsSettings: what the SDK may track for this visitor. */
379
+ AppticsSettings: {
380
+ /** The states setTrackingStatus takes. */
381
+ AP_TRACKING_STATUS: typeof AP_TRACKING_STATUS;
382
+ setTrackingStatus(status: TrackingStatus): void;
383
+ getTrackingStatus(): TrackingStatus;
384
+ };
385
+ }
@@ -0,0 +1,33 @@
1
+ import type { Dict, Properties, UserInfo, UserValidationResult } from '../types.js';
2
+ export declare function getUser(): UserInfo;
3
+ export declare function setUser(userid?: string, groupid?: string, jsonObj?: Properties | UserValidationResult): void;
4
+ export declare function addOrUpdateUser(user_info: Dict): void;
5
+ export declare function getUserInfo(): void;
6
+ export declare function registerUserWithApptics(user_info: Dict): Promise<Dict>;
7
+ /** Builds validated user properties for setUser. */
8
+ export declare class UserBuilder {
9
+ [key: string]: unknown;
10
+ setFirstName(first_name: string): this;
11
+ setLastName(last_name: string): this;
12
+ setCompanyName(company_name: string): this;
13
+ setEmailAddress(email_address: string): this;
14
+ setContactNumber(contact_number: string): this;
15
+ setCountry(country: string): this;
16
+ setRegion(region: string): this;
17
+ setCity(city: string): this;
18
+ setGeoLocation(geo_location: string): this;
19
+ setGender(gender: string): this;
20
+ setPlanType(plan_type: string): this;
21
+ setTimezone(timezone: string): this;
22
+ setLanguage(language: string): this;
23
+ setEngagementScore(engagement_score: number): this;
24
+ setDateOfBirth(date_of_birth: number): this;
25
+ addStringProperty(key: string, value: string): this;
26
+ addBooleanProperty(key: string, value: boolean): this;
27
+ addNumberProperty(key: string, value: number): this;
28
+ setCustomProperties(obj: Record<string, unknown>): this;
29
+ build(): UserValidationResult;
30
+ }
31
+ export declare const users: {
32
+ UserBuilder: typeof UserBuilder;
33
+ };
@@ -0,0 +1,176 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { AP_LOG_MODULE, AP_TRACKING_STATUS } from '../core/constants.js';
3
+ import { _ZAP } from '../core/state.js';
4
+ import { logFailure, Console } from '../core/logger.js';
5
+ import { isEmpty, nowMs, isEmptyObj, cloneMapExcludingKeys } from '../core/utils.js';
6
+ import { user_defaults } from '../core/storage.js';
7
+ import { canTrack, setTrackingStatus } from '../core/consent.js';
8
+ import { rejectIfDisabled, rejectIfOffline, rejectIfNoDeviceIds, postToApptics, apiHeaders } from '../core/transport.js';
9
+ import { userValidateJSON } from '../core/validate.js';
10
+ import { hooks } from '../core/hooks.js';
11
+
12
+ function getUser() {
13
+ return _ZAP._user_info || {}; // no i18n
14
+ }
15
+ /**
16
+ * user/register wants properties as the validated triple — the values, their types, and what
17
+ * was rejected — which is what UserBuilder.build() returns. A plain object passed to setUser
18
+ * is validated here, so both forms go up in the same shape.
19
+ */
20
+ function asUserProperties(jsonObj) {
21
+ var maybeBuilt = jsonObj;
22
+ var built = maybeBuilt && typeof maybeBuilt === 'object' && maybeBuilt.data && maybeBuilt.datatype // no i18n
23
+ ? maybeBuilt
24
+ : userValidateJSON(jsonObj);
25
+ built.message.forEach(function (problem) {
26
+ logFailure(AP_LOG_MODULE.PROPERTIES, 'AppticsUser.setUser: dropped ' + problem.keys.join(', ') + ' (error ' + problem.code + ')'); // no i18n
27
+ });
28
+ return built;
29
+ }
30
+ function setUser(userid, groupid, jsonObj) {
31
+ let _jsonObj = jsonObj || {};
32
+ userid = userid || ''; // no i18n
33
+ groupid = groupid || ''; // no i18n
34
+ if (!canTrack('setUser')) { // no i18n
35
+ return;
36
+ }
37
+ if (isEmpty(userid)) {
38
+ logFailure(AP_LOG_MODULE.PROPERTIES, 'AppticsUser.setUser: Invalid userid'); // no i18n
39
+ return;
40
+ }
41
+ var user_info = {
42
+ mam: userid,
43
+ customergroupid: groupid,
44
+ appversionid: _ZAP._device_info.appversionid || '', // no i18n
45
+ status: 1,
46
+ happendat: nowMs()
47
+ };
48
+ if (!isEmptyObj(_jsonObj)) { // no i18n
49
+ user_info.userproperties = asUserProperties(_jsonObj);
50
+ }
51
+ registerUserWithApptics(user_info).then(function (user_info) {
52
+ Console.log('setUser: ' + JSON.stringify(user_info)); // no i18n
53
+ }).catch(function (err) {
54
+ Console.log(err);
55
+ });
56
+ }
57
+ function addOrUpdateUser(user_info) {
58
+ user_info.status = 1;
59
+ var users = user_defaults.item('users') || []; // no i18n
60
+ users = users.map((item) => ({ ...item, status: 0 }));
61
+ var index = users.findIndex((userobj) => userobj.userid === user_info.userid);
62
+ if (index !== -1) {
63
+ users[index] = { ...users[index], ...user_info };
64
+ }
65
+ else {
66
+ users.push(user_info);
67
+ }
68
+ user_defaults.add('users', users); // no i18n
69
+ // the user setUser registered, on its own as well: what this browser is tracking as now
70
+ user_defaults.add('user_info', users[index !== -1 ? index : users.length - 1]); // no i18n
71
+ }
72
+ function getUserInfo() {
73
+ var stored = user_defaults.item('user_info'); // no i18n
74
+ if (stored && typeof stored === 'object' && !isEmpty(stored.userid)) { // no i18n
75
+ _ZAP._user_info = stored;
76
+ return;
77
+ }
78
+ // registered before user_info was kept: the active one of the users list
79
+ var users = user_defaults.item('users') || []; // no i18n
80
+ var activeuser = {};
81
+ if (users.length > 0) {
82
+ activeuser = users.filter((item) => item.status === 1)[0] || {};
83
+ }
84
+ _ZAP._user_info = activeuser;
85
+ }
86
+ // Function to register the user
87
+ function registerUserWithApptics(user_info) {
88
+ var label = 'registerUserWithApptics'; // no i18n
89
+ var blocked = rejectIfDisabled(label) || rejectIfOffline(label);
90
+ if (blocked) {
91
+ return blocked;
92
+ }
93
+ if (isEmptyObj(user_info)) {
94
+ return Promise.reject(label + ': nothing to register'); // no i18n
95
+ }
96
+ var missing = rejectIfNoDeviceIds(label);
97
+ if (missing) {
98
+ return missing;
99
+ }
100
+ var payload = JSON.stringify(cloneMapExcludingKeys(user_info, ['userid', 'groupid', 'happendat'])); // no i18n
101
+ return postToApptics('reguser', payload, apiHeaders(), label).then(function (result) {
102
+ var data = result.data || {};
103
+ user_info.userid = data.userid;
104
+ user_info.groupid = data.customergroupid;
105
+ setTrackingStatus(AP_TRACKING_STATUS.USAGE_TRACKING_WITH_PII);
106
+ addOrUpdateUser(user_info);
107
+ getUserInfo();
108
+ // the user and their customer group are known now: remote config conditions on them re-apply
109
+ hooks.remoteConfigUserChanged();
110
+ return data;
111
+ });
112
+ }
113
+ /** Builds validated user properties for setUser. */
114
+ class UserBuilder {
115
+ setFirstName(first_name) { this.first_name = first_name; return this; }
116
+ setLastName(last_name) { this.last_name = last_name; return this; }
117
+ setCompanyName(company_name) { this.company_name = company_name; return this; }
118
+ setEmailAddress(email_address) { this.email_address = email_address; return this; }
119
+ setContactNumber(contact_number) { this.contact_number = contact_number; return this; }
120
+ setCountry(country) { this.country = country; return this; }
121
+ setRegion(region) { this.region = region; return this; }
122
+ setCity(city) { this.city = city; return this; }
123
+ setGeoLocation(geo_location) { this.geo_location = geo_location; return this; }
124
+ setGender(gender) { this.gender = gender; return this; }
125
+ setPlanType(plan_type) { this.plan_type = plan_type; return this; }
126
+ setTimezone(timezone) { this.timezone = timezone; return this; }
127
+ setLanguage(language) { this.language = language; return this; }
128
+ setEngagementScore(engagement_score) { this.engagement_score = engagement_score; return this; }
129
+ setDateOfBirth(date_of_birth) { this.date_of_birth = date_of_birth; return this; }
130
+ addStringProperty(key, value) {
131
+ if (typeof value === 'string') { // no i18n
132
+ this[key] = value;
133
+ }
134
+ return this;
135
+ }
136
+ addBooleanProperty(key, value) {
137
+ if (typeof value === 'boolean') { // no i18n
138
+ this[key] = value;
139
+ }
140
+ return this;
141
+ }
142
+ addNumberProperty(key, value) {
143
+ if (typeof value === 'number' && Number.isFinite(value)) { // no i18n
144
+ this[key] = value;
145
+ }
146
+ return this;
147
+ }
148
+ setCustomProperties(obj) {
149
+ if (typeof obj === 'object' && obj !== null) { // no i18n
150
+ for (const [key, value] of Object.entries(obj)) {
151
+ this[key] = value;
152
+ }
153
+ }
154
+ return this;
155
+ }
156
+ build() {
157
+ const user = {};
158
+ const knownFields = [
159
+ 'first_name', 'last_name', 'company_name', 'email_address', 'contact_number',
160
+ 'country', 'region', 'city', 'geo_location', 'gender', 'plan_type', 'timezone',
161
+ 'language', 'engagement_score', 'date_of_birth'
162
+ ]; // no i18n
163
+ knownFields.forEach((field) => {
164
+ if (this[field] !== undefined)
165
+ user[field] = this[field];
166
+ });
167
+ Object.entries(this).forEach(([key, value]) => {
168
+ if (knownFields.indexOf(key) === -1 && typeof value !== 'function') { // no i18n
169
+ user[key] = value;
170
+ }
171
+ });
172
+ return userValidateJSON(user);
173
+ }
174
+ }
175
+
176
+ export { UserBuilder, addOrUpdateUser, getUser, getUserInfo, registerUserWithApptics, setUser };