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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/CHANGELOG.md +87 -0
  2. package/LICENSE +13 -0
  3. package/README.md +747 -11
  4. package/dist/apptics.esm.min.js +3 -0
  5. package/dist/apptics.esm.min.js.map +1 -0
  6. package/dist/apptics.min.js +3 -0
  7. package/dist/apptics.min.js.map +1 -0
  8. package/dist/chunks/batch-BU_mTpm1.min.js +3 -0
  9. package/dist/chunks/batch-BU_mTpm1.min.js.map +1 -0
  10. package/dist/chunks/logs-Bea5zUW_.min.js +3 -0
  11. package/dist/chunks/logs-Bea5zUW_.min.js.map +1 -0
  12. package/dist/cjs/auto-init.d.ts +8 -0
  13. package/dist/cjs/auto-init.js +32 -0
  14. package/dist/cjs/core/attempts.d.ts +28 -0
  15. package/dist/cjs/core/attempts.js +113 -0
  16. package/dist/cjs/core/batch.d.ts +32 -0
  17. package/dist/cjs/core/batch.js +115 -0
  18. package/dist/cjs/core/callsite.d.ts +28 -0
  19. package/dist/cjs/core/callsite.js +93 -0
  20. package/dist/cjs/core/consent.d.ts +23 -0
  21. package/dist/cjs/core/consent.js +130 -0
  22. package/dist/cjs/core/constants.d.ts +212 -0
  23. package/dist/cjs/core/constants.js +299 -0
  24. package/dist/cjs/core/db.d.ts +40 -0
  25. package/dist/cjs/core/db.js +334 -0
  26. package/dist/cjs/core/debug.d.ts +22 -0
  27. package/dist/cjs/core/debug.js +88 -0
  28. package/dist/cjs/core/env.d.ts +28 -0
  29. package/dist/cjs/core/env.js +267 -0
  30. package/dist/cjs/core/framework-id.d.ts +1 -0
  31. package/dist/cjs/core/framework-id.js +9 -0
  32. package/dist/cjs/core/guard.d.ts +2 -0
  33. package/dist/cjs/core/guard.js +72 -0
  34. package/dist/cjs/core/hooks.d.ts +41 -0
  35. package/dist/cjs/core/hooks.js +23 -0
  36. package/dist/cjs/core/logger.d.ts +16 -0
  37. package/dist/cjs/core/logger.js +86 -0
  38. package/dist/cjs/core/state.d.ts +69 -0
  39. package/dist/cjs/core/state.js +78 -0
  40. package/dist/cjs/core/storage.d.ts +46 -0
  41. package/dist/cjs/core/storage.js +229 -0
  42. package/dist/cjs/core/transport.d.ts +83 -0
  43. package/dist/cjs/core/transport.js +441 -0
  44. package/dist/cjs/core/utils.d.ts +26 -0
  45. package/dist/cjs/core/utils.js +175 -0
  46. package/dist/cjs/core/validate.d.ts +18 -0
  47. package/dist/cjs/core/validate.js +233 -0
  48. package/dist/cjs/device/appversion.d.ts +20 -0
  49. package/dist/cjs/device/appversion.js +158 -0
  50. package/dist/cjs/device/index.d.ts +23 -0
  51. package/dist/cjs/device/index.js +372 -0
  52. package/dist/cjs/engagement/api-rules.d.ts +84 -0
  53. package/dist/cjs/engagement/api-rules.js +219 -0
  54. package/dist/cjs/engagement/auto-api.d.ts +7 -0
  55. package/dist/cjs/engagement/auto-api.js +200 -0
  56. package/dist/cjs/engagement/auto-screen.d.ts +16 -0
  57. package/dist/cjs/engagement/auto-screen.js +241 -0
  58. package/dist/cjs/engagement/defined-events.d.ts +23 -0
  59. package/dist/cjs/engagement/defined-events.js +58 -0
  60. package/dist/cjs/engagement/send.d.ts +6 -0
  61. package/dist/cjs/engagement/send.js +99 -0
  62. package/dist/cjs/engagement/session.d.ts +42 -0
  63. package/dist/cjs/engagement/session.js +327 -0
  64. package/dist/cjs/engagement/track.d.ts +56 -0
  65. package/dist/cjs/engagement/track.js +350 -0
  66. package/dist/cjs/errors/send.d.ts +6 -0
  67. package/dist/cjs/errors/send.js +73 -0
  68. package/dist/cjs/errors/track.d.ts +4 -0
  69. package/dist/cjs/errors/track.js +127 -0
  70. package/dist/cjs/feedback/controls.d.ts +31 -0
  71. package/dist/cjs/feedback/controls.js +286 -0
  72. package/dist/cjs/feedback/index.d.ts +8 -0
  73. package/dist/cjs/feedback/index.js +37 -0
  74. package/dist/cjs/feedback/logs.d.ts +40 -0
  75. package/dist/cjs/feedback/logs.js +202 -0
  76. package/dist/cjs/feedback/send.d.ts +25 -0
  77. package/dist/cjs/feedback/send.js +178 -0
  78. package/dist/cjs/feedback/template.d.ts +2 -0
  79. package/dist/cjs/feedback/template.js +162 -0
  80. package/dist/cjs/feedback/ui.d.ts +55 -0
  81. package/dist/cjs/feedback/ui.js +631 -0
  82. package/dist/cjs/heatmap/index.d.ts +16 -0
  83. package/dist/cjs/heatmap/index.js +22 -0
  84. package/dist/cjs/heatmap/send.d.ts +13 -0
  85. package/dist/cjs/heatmap/send.js +82 -0
  86. package/dist/cjs/heatmap/track.d.ts +4 -0
  87. package/dist/cjs/heatmap/track.js +377 -0
  88. package/dist/cjs/index.d.ts +68 -0
  89. package/dist/cjs/index.js +150 -0
  90. package/dist/cjs/lifecycle.d.ts +14 -0
  91. package/dist/cjs/lifecycle.js +538 -0
  92. package/dist/cjs/package.json +3 -0
  93. package/dist/cjs/remoteconfig/custom.d.ts +10 -0
  94. package/dist/cjs/remoteconfig/custom.js +78 -0
  95. package/dist/cjs/remoteconfig/evaluate.d.ts +24 -0
  96. package/dist/cjs/remoteconfig/evaluate.js +171 -0
  97. package/dist/cjs/remoteconfig/fetch.d.ts +24 -0
  98. package/dist/cjs/remoteconfig/fetch.js +214 -0
  99. package/dist/cjs/remoteconfig/index.d.ts +13 -0
  100. package/dist/cjs/remoteconfig/index.js +90 -0
  101. package/dist/cjs/remoteconfig/store.d.ts +18 -0
  102. package/dist/cjs/remoteconfig/store.js +98 -0
  103. package/dist/cjs/remotelog/gate.d.ts +11 -0
  104. package/dist/cjs/remotelog/gate.js +54 -0
  105. package/dist/cjs/remotelog/index.d.ts +25 -0
  106. package/dist/cjs/remotelog/index.js +55 -0
  107. package/dist/cjs/remotelog/logger.d.ts +28 -0
  108. package/dist/cjs/remotelog/logger.js +139 -0
  109. package/dist/cjs/remotelog/send.d.ts +13 -0
  110. package/dist/cjs/remotelog/send.js +153 -0
  111. package/dist/cjs/scheduler.d.ts +8 -0
  112. package/dist/cjs/scheduler.js +78 -0
  113. package/dist/cjs/types.d.ts +312 -0
  114. package/dist/cjs/user/index.d.ts +33 -0
  115. package/dist/cjs/user/index.js +178 -0
  116. package/dist/esm/auto-init.d.ts +8 -0
  117. package/dist/esm/auto-init.js +29 -0
  118. package/dist/esm/core/attempts.d.ts +28 -0
  119. package/dist/esm/core/attempts.js +106 -0
  120. package/dist/esm/core/batch.d.ts +32 -0
  121. package/dist/esm/core/batch.js +108 -0
  122. package/dist/esm/core/callsite.d.ts +28 -0
  123. package/dist/esm/core/callsite.js +89 -0
  124. package/dist/esm/core/consent.d.ts +23 -0
  125. package/dist/esm/core/consent.js +120 -0
  126. package/dist/esm/core/constants.d.ts +212 -0
  127. package/dist/esm/core/constants.js +277 -0
  128. package/dist/esm/core/db.d.ts +40 -0
  129. package/dist/esm/core/db.js +324 -0
  130. package/dist/esm/core/debug.d.ts +22 -0
  131. package/dist/esm/core/debug.js +81 -0
  132. package/dist/esm/core/env.d.ts +28 -0
  133. package/dist/esm/core/env.js +251 -0
  134. package/dist/esm/core/framework-id.d.ts +1 -0
  135. package/dist/esm/core/framework-id.js +7 -0
  136. package/dist/esm/core/guard.d.ts +2 -0
  137. package/dist/esm/core/guard.js +70 -0
  138. package/dist/esm/core/hooks.d.ts +41 -0
  139. package/dist/esm/core/hooks.js +21 -0
  140. package/dist/esm/core/logger.d.ts +16 -0
  141. package/dist/esm/core/logger.js +82 -0
  142. package/dist/esm/core/state.d.ts +69 -0
  143. package/dist/esm/core/state.js +73 -0
  144. package/dist/esm/core/storage.d.ts +46 -0
  145. package/dist/esm/core/storage.js +219 -0
  146. package/dist/esm/core/transport.d.ts +83 -0
  147. package/dist/esm/core/transport.js +425 -0
  148. package/dist/esm/core/utils.d.ts +26 -0
  149. package/dist/esm/core/utils.js +161 -0
  150. package/dist/esm/core/validate.d.ts +18 -0
  151. package/dist/esm/core/validate.js +226 -0
  152. package/dist/esm/device/appversion.d.ts +20 -0
  153. package/dist/esm/device/appversion.js +153 -0
  154. package/dist/esm/device/index.d.ts +23 -0
  155. package/dist/esm/device/index.js +362 -0
  156. package/dist/esm/engagement/api-rules.d.ts +84 -0
  157. package/dist/esm/engagement/api-rules.js +211 -0
  158. package/dist/esm/engagement/auto-api.d.ts +7 -0
  159. package/dist/esm/engagement/auto-api.js +198 -0
  160. package/dist/esm/engagement/auto-screen.d.ts +16 -0
  161. package/dist/esm/engagement/auto-screen.js +238 -0
  162. package/dist/esm/engagement/defined-events.d.ts +23 -0
  163. package/dist/esm/engagement/defined-events.js +55 -0
  164. package/dist/esm/engagement/send.d.ts +6 -0
  165. package/dist/esm/engagement/send.js +96 -0
  166. package/dist/esm/engagement/session.d.ts +42 -0
  167. package/dist/esm/engagement/session.js +315 -0
  168. package/dist/esm/engagement/track.d.ts +56 -0
  169. package/dist/esm/engagement/track.js +340 -0
  170. package/dist/esm/errors/send.d.ts +6 -0
  171. package/dist/esm/errors/send.js +70 -0
  172. package/dist/esm/errors/track.d.ts +4 -0
  173. package/dist/esm/errors/track.js +123 -0
  174. package/dist/esm/feedback/controls.d.ts +31 -0
  175. package/dist/esm/feedback/controls.js +280 -0
  176. package/dist/esm/feedback/index.d.ts +8 -0
  177. package/dist/esm/feedback/index.js +30 -0
  178. package/dist/esm/feedback/logs.d.ts +40 -0
  179. package/dist/esm/feedback/logs.js +188 -0
  180. package/dist/esm/feedback/send.d.ts +25 -0
  181. package/dist/esm/feedback/send.js +175 -0
  182. package/dist/esm/feedback/template.d.ts +2 -0
  183. package/dist/esm/feedback/template.js +159 -0
  184. package/dist/esm/feedback/ui.d.ts +55 -0
  185. package/dist/esm/feedback/ui.js +626 -0
  186. package/dist/esm/heatmap/index.d.ts +16 -0
  187. package/dist/esm/heatmap/index.js +17 -0
  188. package/dist/esm/heatmap/send.d.ts +13 -0
  189. package/dist/esm/heatmap/send.js +79 -0
  190. package/dist/esm/heatmap/track.d.ts +4 -0
  191. package/dist/esm/heatmap/track.js +374 -0
  192. package/dist/esm/index.d.ts +68 -0
  193. package/dist/esm/index.js +122 -0
  194. package/dist/esm/lifecycle.d.ts +14 -0
  195. package/dist/esm/lifecycle.js +534 -0
  196. package/dist/esm/package.json +3 -0
  197. package/dist/esm/remoteconfig/custom.d.ts +10 -0
  198. package/dist/esm/remoteconfig/custom.js +74 -0
  199. package/dist/esm/remoteconfig/evaluate.d.ts +24 -0
  200. package/dist/esm/remoteconfig/evaluate.js +166 -0
  201. package/dist/esm/remoteconfig/fetch.d.ts +24 -0
  202. package/dist/esm/remoteconfig/fetch.js +210 -0
  203. package/dist/esm/remoteconfig/index.d.ts +13 -0
  204. package/dist/esm/remoteconfig/index.js +85 -0
  205. package/dist/esm/remoteconfig/store.d.ts +18 -0
  206. package/dist/esm/remoteconfig/store.js +91 -0
  207. package/dist/esm/remotelog/gate.d.ts +11 -0
  208. package/dist/esm/remotelog/gate.js +48 -0
  209. package/dist/esm/remotelog/index.d.ts +25 -0
  210. package/dist/esm/remotelog/index.js +51 -0
  211. package/dist/esm/remotelog/logger.d.ts +28 -0
  212. package/dist/esm/remotelog/logger.js +136 -0
  213. package/dist/esm/remotelog/send.d.ts +13 -0
  214. package/dist/esm/remotelog/send.js +149 -0
  215. package/dist/esm/scheduler.d.ts +8 -0
  216. package/dist/esm/scheduler.js +74 -0
  217. package/dist/esm/types.d.ts +312 -0
  218. package/dist/esm/user/index.d.ts +33 -0
  219. package/dist/esm/user/index.js +170 -0
  220. package/dist/feedback.esm.min.js +3 -0
  221. package/dist/feedback.esm.min.js.map +1 -0
  222. package/dist/heatmap.esm.min.js +3 -0
  223. package/dist/heatmap.esm.min.js.map +1 -0
  224. package/dist/style.css +1 -0
  225. package/package.json +124 -7
  226. package/src/appticssdk.js +0 -1
@@ -0,0 +1,106 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (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,108 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (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 { shouldTrackOrSendData } from './consent.js';
7
+ import { attemptsExhausted, MAX_ATTEMPTS, resetAttempts } from './attempts.js';
8
+ import { rejectIfDisabled, rejectIfNoDeviceIds, getMetaObj, postKeepalive, apiHeaders, postToApptics } from './transport.js';
9
+
10
+ /** Retries `send` in 500 ms, replacing any retry already scheduled. */
11
+ function defer(send) {
12
+ if (_ZAP._deferSendTimer) {
13
+ clearTimeout(_ZAP._deferSendTimer);
14
+ }
15
+ _ZAP._deferSendTimer = setTimeout(send, 500);
16
+ }
17
+ function clearDefer() {
18
+ if (_ZAP._deferSendTimer) {
19
+ clearTimeout(_ZAP._deferSendTimer);
20
+ _ZAP._deferSendTimer = null;
21
+ }
22
+ }
23
+ /** Only one tab sends a queue at a time. Without the Web Locks API, runs directly (1.x behaviour). */
24
+ function withSendLock(name, run) {
25
+ var locks = typeof navigator !== 'undefined' ? navigator.locks : undefined; // no i18n
26
+ if (!locks || typeof locks.request !== 'function') { // no i18n
27
+ return run();
28
+ }
29
+ return locks.request('apptics-send-' + name, { ifAvailable: true }, function (lock) {
30
+ return lock ? run() : undefined;
31
+ }).then(function () { return undefined; });
32
+ }
33
+ /**
34
+ * The batch to send: closed items within batch_request_timeout days.
35
+ * Expired items are removed from the queue without being sent.
36
+ */
37
+ function freshItems(queue, isClosed, timeOf) {
38
+ return queue.payload().then(function (items) {
39
+ var fresh = [];
40
+ var expired = [];
41
+ items.forEach(function (item) {
42
+ if (!isClosed(item)) {
43
+ return;
44
+ }
45
+ (isExpired(timeOf(item)) ? expired : fresh).push(item);
46
+ });
47
+ return expired.length ? queue.remove(expired).then(function () { return fresh; }) : fresh;
48
+ });
49
+ }
50
+ /**
51
+ * Sends one batch of queued items. Resolves only when the server has accepted it, so the caller
52
+ * removes the items then and not before: a batch that fails stays queued and goes again on the
53
+ * next pass, as attempt 2, which `attempt` and `firstattempttime` let the server recognise as a
54
+ * copy rather than store twice.
55
+ *
56
+ * With `forget` (the page is closing) it goes by keepalive, and the promise settles if the answer
57
+ * arrives before the page is gone. See postKeepalive.
58
+ *
59
+ * Five attempts is the cap, because `attempt` is declared regex="[1-5]" and a sixth would be
60
+ * refused for the param rather than for the payload.
61
+ */
62
+ function sendBatch(path, label, _payload, forget) {
63
+ var blocked = rejectIfDisabled(label);
64
+ if (blocked) {
65
+ return blocked;
66
+ }
67
+ if (!shouldTrackOrSendData()) {
68
+ return Promise.reject(label + ': tracking is off'); // no i18n
69
+ }
70
+ if (isEmptyObj(_payload)) {
71
+ return Promise.reject(label + ': nothing to send'); // no i18n
72
+ }
73
+ var missing = rejectIfNoDeviceIds(label);
74
+ if (missing) {
75
+ return missing;
76
+ }
77
+ if (!_payload.hasOwnProperty('meta')) { // no i18n
78
+ _payload.meta = getMetaObj();
79
+ }
80
+ if (attemptsExhausted(path)) {
81
+ // five passes without a confirmed landing. Keeping it would block every later batch
82
+ // behind a payload the proxy will now refuse for its attempt number alone
83
+ warnAlways('apptics: dropping a ' + label + ' batch after ' + MAX_ATTEMPTS + ' attempts'); // no i18n
84
+ resetAttempts(path);
85
+ return Promise.resolve({ result: 'success' }); // no i18n
86
+ }
87
+ Console.log(label + ': Payload size : ' + (sizeof(_payload) / 1024)); // no i18n
88
+ var body = JSON.stringify(_payload);
89
+ return forget
90
+ ? postKeepalive(path, body, apiHeaders(), label)
91
+ : postToApptics(path, body, apiHeaders(), label);
92
+ }
93
+ /**
94
+ * Hands a send's outcome back to a sender. Normally the sender waits for it. While the page
95
+ * closes it does not: the request is already out, and waiting would hold the next queue's send
96
+ * until after the page has gone. The outcome is still handled whenever it arrives.
97
+ */
98
+ function awaitUnlessClosing(landed, forget, label) {
99
+ if (!forget) {
100
+ return landed.then(function () { return undefined; });
101
+ }
102
+ landed.catch(function (err) {
103
+ Console.log(label + ': not confirmed before the page closed, kept for the next send: ' + String(err)); // no i18n
104
+ });
105
+ return undefined;
106
+ }
107
+
108
+ export { awaitUnlessClosing, clearDefer, defer, freshItems, sendBatch, withSendLock };
@@ -0,0 +1,28 @@
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
+ * The frame `skip` frames down a stack, counting only the ones that name a file — V8 heads its
20
+ * stacks with an `Error` line and Firefox does not, so counting raw lines would read a different
21
+ * frame in each browser.
22
+ */
23
+ export declare function callSiteFromStack(stack: string | undefined, skip: number): CallSite;
24
+ /**
25
+ * Where the caller `skip` levels above this call sits. `skip` is 0 for this function's own
26
+ * caller; each wrapper between that caller and the place worth reporting adds one.
27
+ */
28
+ export declare function callSite(skip: number): CallSite;
@@ -0,0 +1,89 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (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
+ /** logSDK declares max-len="100" on filename. */
12
+ const FILENAME_MAX = 100;
13
+ /**
14
+ * The file and line out of one stack frame, in either shape a browser produces:
15
+ * V8: ` at doThing (https://host/app.js:12:34)`
16
+ * Firefox/Safari: `doThing@https://host/app.js:12:34`
17
+ * Both end in `:line:column`, which is the only part that is the same everywhere, so the match is
18
+ * anchored there and the column is read only so that it can be thrown away — without it the
19
+ * pattern would take the column for the line.
20
+ */
21
+ const FRAME = /([^\s(@]+):(\d+):(\d+)\)?$/;
22
+ /** `https://host/path/app.js?v=2` -> `app.js`. The url would not fit in 100 characters. */
23
+ function basename(url) {
24
+ var path = url.split(/[?#]/)[0] || url;
25
+ var parts = path.split('/');
26
+ return (parts[parts.length - 1] || path).slice(0, FILENAME_MAX);
27
+ }
28
+ /**
29
+ * The function a frame names, in either shape:
30
+ * V8: `at doThing (` — or `at async doThing (`
31
+ * Firefox/Safari: `doThing@`
32
+ * A frame without one (`at https://…` or `@https://…`) is an anonymous caller, and gets ''.
33
+ */
34
+ const FRAME_FN_V8 = /^at\s+(?:async\s+)?(.+?)\s+\(/;
35
+ const FRAME_FN_OTHER = /^([^@\s]+)@/;
36
+ function frameFunction(frame) {
37
+ var match = FRAME_FN_V8.exec(frame) || FRAME_FN_OTHER.exec(frame);
38
+ return match ? (match[1] || '') : ''; // no i18n
39
+ }
40
+ function parseFrame(line) {
41
+ var trimmed = line.trim();
42
+ var match = FRAME.exec(trimmed);
43
+ if (match === null) {
44
+ return null;
45
+ }
46
+ var line_no = Number(match[2]);
47
+ if (!isFinite(line_no)) {
48
+ return null;
49
+ }
50
+ return { filename: basename(match[1] || ''), linenumber: line_no, fn: frameFunction(trimmed) };
51
+ }
52
+ /**
53
+ * The frame `skip` frames down a stack, counting only the ones that name a file — V8 heads its
54
+ * stacks with an `Error` line and Firefox does not, so counting raw lines would read a different
55
+ * frame in each browser.
56
+ */
57
+ function callSiteFromStack(stack, skip) {
58
+ if (!stack) {
59
+ return NO_CALL_SITE;
60
+ }
61
+ var lines = stack.split('\n');
62
+ var seen = 0;
63
+ for (var i = 0; i < lines.length; i++) {
64
+ var frame = parseFrame(lines[i] || '');
65
+ if (frame === null) {
66
+ continue;
67
+ }
68
+ if (seen++ < skip) {
69
+ continue;
70
+ }
71
+ return frame;
72
+ }
73
+ return NO_CALL_SITE;
74
+ }
75
+ /**
76
+ * Where the caller `skip` levels above this call sits. `skip` is 0 for this function's own
77
+ * caller; each wrapper between that caller and the place worth reporting adds one.
78
+ */
79
+ function callSite(skip) {
80
+ try {
81
+ // +1 for this function's own frame, which is never the answer
82
+ return callSiteFromStack(new Error().stack, skip + 1);
83
+ }
84
+ catch (err) {
85
+ return NO_CALL_SITE;
86
+ }
87
+ }
88
+
89
+ export { NO_CALL_SITE, callSite, callSiteFromStack };
@@ -0,0 +1,23 @@
1
+ import type { TrackingStatus } from '../types.js';
2
+ /** DNT counts only when not ignored; when it counts, tracking switches to NO_TRACKING. */
3
+ export declare function hasDoNotTrackEnabled(): boolean;
4
+ export declare function opt_in_status(): TrackingStatus;
5
+ export declare function shouldTrackOrSendData(): boolean;
6
+ /**
7
+ * The guard every tracking call starts with: init() has run, the client isn't a crawler,
8
+ * and consent / server flags allow tracking.
9
+ */
10
+ export declare function canTrack(caller: string): boolean;
11
+ /** canTrack plus the server's `engagementtracking` flag from getupdates (events, screens, sessions, api calls). */
12
+ export declare function canTrackEngagement(caller: string): boolean;
13
+ /**
14
+ * canTrack plus the server's heatmap flag (getsdkconfig module 18).
15
+ *
16
+ * Heatmap rode the engagement flag until v2 gave it one of its own, which matters: an app may
17
+ * well want events while declining to have every click's coordinates recorded.
18
+ */
19
+ export declare function canTrackHeatmap(caller: string): boolean;
20
+ /** canTrack plus the server's `errortracking` flag from getupdates. */
21
+ export declare function canTrackErrors(caller: string): boolean;
22
+ export declare function setTrackingStatus(trackingState: TrackingStatus): void;
23
+ export declare function getTrackingStatus(): TrackingStatus;
@@ -0,0 +1,120 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { AP_TRACKING_STATUS } from './constants.js';
3
+ import { _ZAP } from './state.js';
4
+ import { Console } from './logger.js';
5
+ import { isEmpty, isSuccess } from './utils.js';
6
+ import { tracking_preference } from './storage.js';
7
+ import { isDntOn, is_apptics_disabled } from './env.js';
8
+ import { hooks } from './hooks.js';
9
+
10
+ /** DNT counts only when not ignored; when it counts, tracking switches to NO_TRACKING. */
11
+ function hasDoNotTrackEnabled() {
12
+ if (_ZAP._ignoreDnt) {
13
+ return false;
14
+ }
15
+ if (isDntOn()) {
16
+ Console.warn('hasDoNotTrackEnabled: DoNotTrack is enabled'); // no i18n
17
+ setTrackingStatus(AP_TRACKING_STATUS.NO_TRACKING);
18
+ Console.log('hasDoNotTrackEnabled: Setting tracking status to NO_TRACKING'); // no i18n
19
+ return true;
20
+ }
21
+ return false;
22
+ }
23
+ function opt_in_status() {
24
+ if (hasDoNotTrackEnabled()) {
25
+ Console.warn('opt_in_status: It seems "Do Not Track" is enabled in this browser. Please enable tracking in the browser settings to continue tracking.'); // no i18n
26
+ return AP_TRACKING_STATUS.NO_TRACKING;
27
+ }
28
+ var status = tracking_preference.opt_in_status();
29
+ if (status == -1) {
30
+ Console.warn('opt_in_status: You are opted out of Apptics tracking. This will prevent the our SDK from sending no data to our server.'); // no i18n
31
+ }
32
+ return status;
33
+ }
34
+ function shouldTrackOrSendData() {
35
+ var optInStatus = opt_in_status();
36
+ return optInStatus > -1 && _ZAP._shouldTrack;
37
+ }
38
+ /**
39
+ * The guard every tracking call starts with: init() has run, the client isn't a crawler,
40
+ * and consent / server flags allow tracking.
41
+ */
42
+ function canTrack(caller) {
43
+ if (!_ZAP._token) {
44
+ Console.warn('apptics.' + caller + ': You must call apptics.init() first'); // no i18n
45
+ return false;
46
+ }
47
+ if (is_apptics_disabled()) {
48
+ return false;
49
+ }
50
+ return shouldTrackOrSendData();
51
+ }
52
+ /** canTrack plus the server's `engagementtracking` flag from getupdates (events, screens, sessions, api calls). */
53
+ function canTrackEngagement(caller) {
54
+ if (!canTrack(caller)) {
55
+ return false;
56
+ }
57
+ if (!_ZAP._engagementTracking) {
58
+ Console.log('apptics.' + caller + ': engagement tracking is turned off by the server'); // no i18n
59
+ return false;
60
+ }
61
+ return true;
62
+ }
63
+ /**
64
+ * canTrack plus the server's heatmap flag (getsdkconfig module 18).
65
+ *
66
+ * Heatmap rode the engagement flag until v2 gave it one of its own, which matters: an app may
67
+ * well want events while declining to have every click's coordinates recorded.
68
+ */
69
+ function canTrackHeatmap(caller) {
70
+ if (!canTrack(caller)) {
71
+ return false;
72
+ }
73
+ if (!_ZAP._heatmapTracking) {
74
+ Console.log('apptics.' + caller + ': heatmap tracking is turned off by the server'); // no i18n
75
+ return false;
76
+ }
77
+ return true;
78
+ }
79
+ /** canTrack plus the server's `errortracking` flag from getupdates. */
80
+ function canTrackErrors(caller) {
81
+ if (!canTrack(caller)) {
82
+ return false;
83
+ }
84
+ if (!_ZAP._errorTracking) {
85
+ Console.log('apptics.' + caller + ': error tracking is turned off by the server'); // no i18n
86
+ return false;
87
+ }
88
+ return true;
89
+ }
90
+ function setTrackingStatus(trackingState) {
91
+ if (isEmpty(trackingState)) {
92
+ Console.warn('setTrackingStatus: trackingStatus is Empty'); // no i18n
93
+ return;
94
+ }
95
+ if (tracking_preference.opt_in_status() == trackingState) {
96
+ return;
97
+ }
98
+ tracking_preference.update_status(trackingState);
99
+ _ZAP._devicestatus = tracking_preference.opt_in_status();
100
+ _ZAP._isanonrequired = tracking_preference.opt_in_status() == AP_TRACKING_STATUS.USAGE_TRACKING_WITH_PII ? false : _ZAP._isanonrequired;
101
+ if (tracking_preference.opt_in_status() != AP_TRACKING_STATUS.NO_TRACKING) {
102
+ Console.log('setTrackingStatus: Updating device info with new tracking status'); // no i18n
103
+ hooks.updateDevice(_ZAP._device_info).then(function (result) {
104
+ if (isSuccess(result)) {
105
+ Console.log('setTrackingStatus: Device info updated with new tracking status' + JSON.stringify(result.data)); // no i18n
106
+ Console.dir(result.data);
107
+ }
108
+ else {
109
+ Console.log('setTrackingStatus: Error updating device info with new tracking status: ' + JSON.stringify(result)); // no i18n
110
+ }
111
+ }).catch(function (err) {
112
+ Console.warn('setTrackingStatus: Error updating device info with new tracking status: ' + JSON.stringify(err)); // no i18n
113
+ });
114
+ }
115
+ }
116
+ function getTrackingStatus() {
117
+ return opt_in_status();
118
+ }
119
+
120
+ export { canTrack, canTrackEngagement, canTrackErrors, canTrackHeatmap, getTrackingStatus, hasDoNotTrackEnabled, opt_in_status, setTrackingStatus, shouldTrackOrSendData };