@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,309 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { Console } from '../core/logger.js';
3
+ import { hooks } from '../core/hooks.js';
4
+ import { user_defaults } from '../core/storage.js';
5
+ import { isEmpty } from '../core/utils.js';
6
+ import { _ZAP } from '../core/state.js';
7
+ import { hasLogLines, hasDiagnostics, logText, diagnosticsText } from './logs.js';
8
+
9
+ /**
10
+ * The three controls at the top and bottom of the feedback form: the user picker, the
11
+ * log/diagnostics toggles with their data viewer, and dragging the dialog by its header.
12
+ *
13
+ * They live here rather than in ui.ts so that init() stays about assembling the modal, and each
14
+ * control can be wired (and read back) on its own.
15
+ */
16
+ const ANONYMOUS = 'anonymous'; // no i18n
17
+ const ANONYMOUS_LABEL = 'Anonymous'; // no i18n
18
+ /** Read by core/transport when it builds the feedback request's parameters. */
19
+ const userChoice = { anonymous: true, userid: '', groupid: '' }; // no i18n
20
+ /** Whether the next submission carries the stored logs and diagnostics. Unset means "decide from what is stored". */
21
+ const logChoice = {};
22
+ function resetUserChoice() {
23
+ userChoice.anonymous = true;
24
+ userChoice.userid = ''; // no i18n
25
+ userChoice.groupid = ''; // no i18n
26
+ }
27
+ /**
28
+ * Who a sendFeedback() report, made without the form, is attributed to: nobody when `anonymous`,
29
+ * else the user AppticsUser.setUser set (or the active registered one, status 1). Returns a function
30
+ * that puts back the choice that was there, so a form left open keeps its own.
31
+ */
32
+ function chooseUserForSend(anonymous) {
33
+ var before = { anonymous: userChoice.anonymous, userid: userChoice.userid, groupid: userChoice.groupid };
34
+ resetUserChoice();
35
+ if (!anonymous) {
36
+ // the user setUser set on this page, else the active one of those registered before
37
+ var active = !isEmpty(_ZAP._user_info.userid) ? _ZAP._user_info : null;
38
+ storedUsers().forEach(function (user) {
39
+ if (!active && user && user.status == 1 && !isEmpty(user.userid)) {
40
+ active = user;
41
+ }
42
+ });
43
+ if (active) {
44
+ userChoice.anonymous = false;
45
+ userChoice.userid = String(active.userid);
46
+ userChoice.groupid = String(active.groupid || ''); // no i18n
47
+ }
48
+ }
49
+ return function restore() {
50
+ userChoice.anonymous = before.anonymous;
51
+ userChoice.userid = before.userid;
52
+ userChoice.groupid = before.groupid;
53
+ };
54
+ }
55
+ /** Every distinct registered user, by the address the picker shows. */
56
+ function storedUsers() {
57
+ var users = user_defaults.item('users'); // no i18n
58
+ return Array.isArray(users) ? users : [];
59
+ }
60
+ function pickerItems(users) {
61
+ var items = [{ value: ANONYMOUS, label: ANONYMOUS_LABEL }];
62
+ var seen = {};
63
+ users.forEach(function (user) {
64
+ var mam = user && user.mam;
65
+ if (!isEmpty(mam) && !seen[mam]) {
66
+ seen[mam] = true;
67
+ items.push({ value: String(mam), label: String(mam) });
68
+ }
69
+ });
70
+ return items;
71
+ }
72
+ const SVG_NS = 'http://www.w3.org/2000/svg'; // no i18n
73
+ /** The tick beside the picked option. */
74
+ function tickIcon() {
75
+ var svg = document.createElementNS(SVG_NS, 'svg'); // no i18n
76
+ svg.setAttribute('viewBox', '0 0 14 10'); // no i18n
77
+ svg.setAttribute('width', '14'); // no i18n
78
+ svg.setAttribute('height', '10'); // no i18n
79
+ svg.setAttribute('fill', 'none'); // no i18n
80
+ var path = document.createElementNS(SVG_NS, 'path'); // no i18n
81
+ path.setAttribute('d', 'M1 5l4 4 8-8'); // no i18n
82
+ path.setAttribute('stroke', '#0078d4'); // no i18n
83
+ path.setAttribute('stroke-width', '2'); // no i18n
84
+ path.setAttribute('stroke-linecap', 'round'); // no i18n
85
+ path.setAttribute('stroke-linejoin', 'round'); // no i18n
86
+ svg.appendChild(path);
87
+ return svg;
88
+ }
89
+ /**
90
+ * The "User" dropdown above the description. It lists Anonymous plus every registered user, and
91
+ * starts on the active one (status 1) unless the caller asked for anonymous.
92
+ */
93
+ function wireUserPicker(modal, forceAnonymous) {
94
+ var trigger = modal.querySelector('#zasdkEmailTrigger'); // no i18n
95
+ var panel = modal.querySelector('#zasdkEmailPanel'); // no i18n
96
+ var label = modal.querySelector('#zasdkEmailLabel'); // no i18n
97
+ var list = modal.querySelector('#zasdkEmailList'); // no i18n
98
+ var dropdown = modal.querySelector('#zasdkEmailDropdown'); // no i18n
99
+ if (!trigger || !panel || !label || !list || !dropdown) {
100
+ return;
101
+ }
102
+ var users = storedUsers();
103
+ var items = pickerItems(users);
104
+ var selected = ANONYMOUS;
105
+ resetUserChoice();
106
+ if (!forceAnonymous) {
107
+ var active = null;
108
+ users.forEach(function (user) {
109
+ if (!active && user && user.status == 1 && !isEmpty(user.mam)) {
110
+ active = user;
111
+ }
112
+ });
113
+ if (active) {
114
+ select(String(active.mam));
115
+ }
116
+ }
117
+ function select(value) {
118
+ selected = value;
119
+ userChoice.anonymous = value === ANONYMOUS;
120
+ var matched = null;
121
+ if (!userChoice.anonymous) {
122
+ users.forEach(function (user) {
123
+ if (!matched && user && user.mam === value) {
124
+ matched = user;
125
+ }
126
+ });
127
+ }
128
+ userChoice.userid = matched ? String(matched.userid || '') : ''; // no i18n
129
+ userChoice.groupid = matched ? String(matched.groupid || '') : ''; // no i18n
130
+ label.textContent = userChoice.anonymous ? ANONYMOUS_LABEL : value;
131
+ render();
132
+ }
133
+ function render() {
134
+ list.innerHTML = ''; // no i18n
135
+ if (items.length === 0) {
136
+ var empty = document.createElement('div'); // no i18n
137
+ empty.className = 'zasdk-select-empty'; // no i18n
138
+ empty.textContent = 'No users to choose from'; // no i18n
139
+ list.appendChild(empty);
140
+ return;
141
+ }
142
+ items.forEach(function (item) {
143
+ var isSelected = item.value === selected;
144
+ var option = document.createElement('li'); // no i18n
145
+ option.className = 'zasdk-select-option' + (isSelected ? ' zasdk-option-selected' : ''); // no i18n
146
+ option.setAttribute('data-value', item.value); // no i18n
147
+ var text = document.createElement('span'); // no i18n
148
+ text.textContent = item.label;
149
+ option.appendChild(text);
150
+ if (isSelected) {
151
+ option.appendChild(tickIcon());
152
+ }
153
+ list.appendChild(option);
154
+ });
155
+ }
156
+ trigger.addEventListener('click', function (event) {
157
+ event.stopPropagation();
158
+ var open = panel.style.display !== 'none'; // no i18n
159
+ panel.style.display = open ? 'none' : 'block'; // no i18n
160
+ if (!open) {
161
+ render();
162
+ }
163
+ });
164
+ list.addEventListener('click', function (event) {
165
+ var option = event.target.closest('.zasdk-select-option'); // no i18n
166
+ if (!option) {
167
+ return;
168
+ }
169
+ select(String(option.getAttribute('data-value'))); // no i18n
170
+ panel.style.display = 'none'; // no i18n
171
+ });
172
+ // closing on focusout rather than a document click keeps it working inside a shadow root
173
+ dropdown.setAttribute('tabindex', '0'); // no i18n
174
+ dropdown.addEventListener('focusout', function (event) {
175
+ if (!dropdown.contains(event.relatedTarget)) {
176
+ panel.style.display = 'none'; // no i18n
177
+ }
178
+ });
179
+ render();
180
+ }
181
+ /** Shows `content` in the viewer panel over the form. */
182
+ function openViewer(modal, title, content) {
183
+ var viewer = modal.querySelector('#zasdkDataViewer'); // no i18n
184
+ var viewerTitle = modal.querySelector('#zasdkViewerTitle'); // no i18n
185
+ var viewerContent = modal.querySelector('#zasdkViewerContent'); // no i18n
186
+ if (!viewer || !viewerTitle || !viewerContent) {
187
+ return;
188
+ }
189
+ viewerTitle.textContent = title;
190
+ viewerContent.textContent = content || '(No data available)'; // no i18n
191
+ viewer.style.display = 'flex'; // no i18n
192
+ }
193
+ /**
194
+ * The two "Include …" switches and the viewer behind their View links. A row is shown only when
195
+ * there is something to include, and is then on by default, so a submission carries what the app
196
+ * recorded unless the user turns it off.
197
+ */
198
+ function wireLogControls(modal, opts) {
199
+ var logToggle = modal.querySelector('#zasdkIncludeLogToggle'); // no i18n
200
+ var diagToggle = modal.querySelector('#zasdkIncludeDiagToggle'); // no i18n
201
+ var section = modal.querySelector('.zasdk-toggles-section'); // no i18n
202
+ var separator = modal.querySelector('.zasdk-toggle-separator'); // no i18n
203
+ var viewLogs = modal.querySelector('#zasdkViewLogsBtn'); // no i18n
204
+ var viewDiag = modal.querySelector('#zasdkViewDiagBtn'); // no i18n
205
+ var viewerClose = modal.querySelector('#zasdkViewerClose'); // no i18n
206
+ var viewer = modal.querySelector('#zasdkDataViewer'); // no i18n
207
+ if (!logToggle || !diagToggle || !section) {
208
+ return;
209
+ }
210
+ var logRow = logToggle.closest('.zasdk-toggle-row'); // no i18n
211
+ var diagRow = diagToggle.closest('.zasdk-toggle-row'); // no i18n
212
+ logChoice.includeLog = opts.includeLog === true ? true : undefined;
213
+ logChoice.includeDyninfo = opts.includeDyninfo === true ? true : undefined;
214
+ // hidden until the reads come back, so an empty section never flashes into view
215
+ section.style.display = 'none'; // no i18n
216
+ Promise.all([hasLogLines(), hasDiagnostics()]).then(function ([anyLogs, anyDiagnostics]) {
217
+ if (logRow)
218
+ logRow.style.display = anyLogs ? '' : 'none'; // no i18n
219
+ if (diagRow)
220
+ diagRow.style.display = anyDiagnostics ? '' : 'none'; // no i18n
221
+ if (separator)
222
+ separator.style.display = anyLogs && anyDiagnostics ? '' : 'none'; // no i18n
223
+ section.style.display = anyLogs || anyDiagnostics ? '' : 'none'; // no i18n
224
+ // on when there is data, unless the caller already decided
225
+ logToggle.checked = opts.includeLog === true || anyLogs;
226
+ diagToggle.checked = opts.includeDyninfo === true || anyDiagnostics;
227
+ logChoice.includeLog = logToggle.checked;
228
+ logChoice.includeDyninfo = diagToggle.checked;
229
+ }).catch(function (err) {
230
+ Console.warn('apptics: could not read the stored logs: ' + String(err)); // no i18n
231
+ });
232
+ logToggle.addEventListener('change', function () {
233
+ logChoice.includeLog = logToggle.checked;
234
+ });
235
+ diagToggle.addEventListener('change', function () {
236
+ logChoice.includeDyninfo = diagToggle.checked;
237
+ });
238
+ if (viewLogs) {
239
+ viewLogs.addEventListener('click', function () {
240
+ logText().then(function (text) {
241
+ openViewer(modal, 'System Logs', text); // no i18n
242
+ });
243
+ });
244
+ }
245
+ if (viewDiag) {
246
+ viewDiag.addEventListener('click', function () {
247
+ diagnosticsText().then(function (text) {
248
+ openViewer(modal, 'Diagnostic Information', text); // no i18n
249
+ });
250
+ });
251
+ }
252
+ if (viewerClose && viewer) {
253
+ viewerClose.addEventListener('click', function () {
254
+ viewer.style.display = 'none'; // no i18n
255
+ });
256
+ }
257
+ }
258
+ /**
259
+ * Drags the dialog by its header. The right/bottom placement from the stylesheet is converted to
260
+ * an explicit left/top on the first drag, so the offsets have something to add to, and the box is
261
+ * kept inside the viewport.
262
+ */
263
+ function wireDrag(box) {
264
+ var header = box.querySelector('.zasdk-header'); // no i18n
265
+ if (!header) {
266
+ return;
267
+ }
268
+ var startX = 0, startY = 0, boxLeft = 0, boxTop = 0, dragging = false;
269
+ header.addEventListener('mousedown', function (event) {
270
+ if (event.target.closest('.zasdk-close')) { // no i18n
271
+ return; // the close button is not a drag handle
272
+ }
273
+ if (!box.style.left || box.style.left === 'auto') { // no i18n
274
+ var rect = box.getBoundingClientRect();
275
+ box.style.right = 'auto'; // no i18n
276
+ box.style.bottom = 'auto'; // no i18n
277
+ box.style.left = rect.left + 'px'; // no i18n
278
+ box.style.top = rect.top + 'px'; // no i18n
279
+ }
280
+ dragging = true;
281
+ startX = event.clientX;
282
+ startY = event.clientY;
283
+ boxLeft = parseInt(box.style.left, 10);
284
+ boxTop = parseInt(box.style.top, 10);
285
+ header.style.cursor = 'grabbing'; // no i18n
286
+ event.preventDefault();
287
+ });
288
+ document.addEventListener('mousemove', function (event) {
289
+ if (!dragging) {
290
+ return;
291
+ }
292
+ var left = boxLeft + (event.clientX - startX);
293
+ var top = boxTop + (event.clientY - startY);
294
+ box.style.left = Math.max(0, Math.min(left, window.innerWidth - box.offsetWidth)) + 'px'; // no i18n
295
+ box.style.top = Math.max(0, Math.min(top, window.innerHeight - box.offsetHeight)) + 'px'; // no i18n
296
+ });
297
+ document.addEventListener('mouseup', function () {
298
+ if (dragging) {
299
+ dragging = false;
300
+ header.style.cursor = 'grab'; // no i18n
301
+ }
302
+ });
303
+ }
304
+ // core/transport asks for the picked user when it builds the feedback request's parameters
305
+ hooks.feedbackUser = function () {
306
+ return userChoice.anonymous || isEmpty(userChoice.userid) ? null : userChoice;
307
+ };
308
+
309
+ export { chooseUserForSend, logChoice, userChoice, wireDrag, wireLogControls, wireUserPicker };
@@ -0,0 +1,9 @@
1
+ import type { AppticsFeedbackApi } from '../types.js';
2
+ export type { FeedbackOpenOptions, SendFeedbackOptions } from '../types.js';
3
+ /**
4
+ * Android's AppticsFeedback: the form, sending feedback without it, and the context recorded for
5
+ * the next one. Every feedback call, addFeedbackLog and addDiagnosticsInfo included, is here and
6
+ * only here: the main entry has no AppticsFeedback.
7
+ */
8
+ export declare const AppticsFeedback: AppticsFeedbackApi;
9
+ export default AppticsFeedback;
@@ -0,0 +1,51 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { forward, guard } from '../core/guard.js';
3
+ import { AP_FEEDBACK_TYPE } from '../core/constants.js';
4
+ import { Console } from '../core/logger.js';
5
+ import { ready } from '../lifecycle.js';
6
+ import { setFeedbackTheme, sendFeedback, feedbackFormClose, feedbackFormOpen } from './ui.js';
7
+ import { addDiagnosticsInfo, addFeedbackLog } from './logs.js';
8
+
9
+ /**
10
+ * Optional feedback modal, shipped as its own entry point:
11
+ * import { AppticsFeedback } from '@zoho_apptics/apptics-js-sdk/feedback';
12
+ * AppticsFeedback.feedbackFormOpen();
13
+ * Apps that never import it don't pay for the modal or its markup.
14
+ * The <script> build includes it, so snippet users are unaffected.
15
+ */
16
+ const feedbackFormOpenGuarded = guard('AppticsFeedback.feedbackFormOpen', feedbackFormOpen); // no i18n
17
+ const feedbackFormCloseGuarded = guard('AppticsFeedback.feedbackFormClose', feedbackFormClose); // no i18n
18
+ const addFeedbackLogGuarded = guard('AppticsFeedback.addFeedbackLog', addFeedbackLog); // no i18n
19
+ const addDiagnosticsInfoGuarded = guard('AppticsFeedback.addDiagnosticsInfo', addDiagnosticsInfo); // no i18n
20
+ const setFeedbackThemeGuarded = guard('AppticsFeedback.setFeedbackTheme', setFeedbackTheme); // no i18n
21
+ /** Resolves once the feedback is sent; rejects when it wasn't (SDK not started, offline, refused). */
22
+ const sendFeedbackGuarded = guard('AppticsFeedback.sendFeedback', function (...args) {
23
+ return ready().then(function (started) {
24
+ if (!started) {
25
+ throw new Error('AppticsFeedback.sendFeedback: not sent, the SDK has not started; call Apptics.init() first'); // no i18n
26
+ }
27
+ return sendFeedback(...args);
28
+ }).catch(function (err) {
29
+ Console.error('AppticsFeedback.sendFeedback failed:', err); // no i18n
30
+ throw err;
31
+ });
32
+ });
33
+ /* each call a function of its own, with the parameter names the console shows (see forward) */
34
+ /**
35
+ * Android's AppticsFeedback: the form, sending feedback without it, and the context recorded for
36
+ * the next one. Every feedback call, addFeedbackLog and addDiagnosticsInfo included, is here and
37
+ * only here: the main entry has no AppticsFeedback.
38
+ */
39
+ const AppticsFeedback = {
40
+ /** The feedback types: BUG, FEEDBACK, HELP, REPORT. */
41
+ AP_FEEDBACK_TYPE: AP_FEEDBACK_TYPE,
42
+ feedbackFormOpen: function feedbackFormOpen(options) { return forward(feedbackFormOpenGuarded, arguments); },
43
+ feedbackFormClose: function feedbackFormClose() { return forward(feedbackFormCloseGuarded, arguments); },
44
+ sendFeedback: function sendFeedback(options) { return forward(sendFeedbackGuarded, arguments); },
45
+ addFeedbackLog: function addFeedbackLog(message) { return forward(addFeedbackLogGuarded, arguments); },
46
+ addDiagnosticsInfo: function addDiagnosticsInfo(heading, key, value) { return forward(addDiagnosticsInfoGuarded, arguments); },
47
+ /** The form's theme from now on, and of a form open now: 'light', 'dark' or 'auto'. */
48
+ setFeedbackTheme: function setFeedbackTheme(theme) { return forward(setFeedbackThemeGuarded, arguments); },
49
+ };
50
+
51
+ export { AppticsFeedback, AppticsFeedback as default };
@@ -0,0 +1,45 @@
1
+ /** Neither rendered file is sent above this size (the 1.x limit). */
2
+ export declare const MAX_LOG_FILE_SIZE: number;
3
+ export declare const LOG_FILE_NAME = "feedbacklog.txt";
4
+ export declare const DYNINFO_FILE_NAME = "dyninfo.txt";
5
+ /** One rendered file, with the ids to remove once the server has it. */
6
+ export interface RenderedFile {
7
+ file: File;
8
+ ids: string[];
9
+ }
10
+ /** Drops the oldest entries once the store is over MAX_ENTRIES. */
11
+ export declare function trimStoredLogs(): Promise<void>;
12
+ /**
13
+ * Records a timestamped line for the next feedback submission, sent as feedbacklog.txt.
14
+ * Ignores anything that isn't a non-empty string, as 1.x did.
15
+ */
16
+ export declare function addFeedbackLog(message: string): void;
17
+ /**
18
+ * Records a diagnostics entry, `value` under `key` in the `heading` block of dyninfo.txt. All three
19
+ * are required: an entry without a value says nothing, so it is refused and the console says why.
20
+ * A value of 0 or false is a value.
21
+ */
22
+ export declare function addDiagnosticsInfo(heading: string, key: string, value: unknown): void;
23
+ /** Removes every stored entry. */
24
+ export declare function clearFeedbackLogs(): Promise<void>;
25
+ /** Removes the entries a submission carried, by the ids the rendered files reported. */
26
+ export declare function feedbacklog_transactions_remove(sentIds: string[]): Promise<void>;
27
+ /** feedbacklog.txt from the stored log lines, or null when there are none. */
28
+ export declare function toLogFile(): Promise<RenderedFile | null>;
29
+ /**
30
+ * The log lines for showing in the modal before sending, each time in the visitor's local zone.
31
+ * The file that is sent (toLogFile) keeps the ISO 8601 UTC stamps, so the server and anything
32
+ * that parses it are unaffected.
33
+ */
34
+ export declare function logText(): Promise<string>;
35
+ /** The diagnostics entries as dyninfo.txt would carry them, without the device info block. */
36
+ export declare function diagnosticsText(): Promise<string>;
37
+ /** True when any log line is waiting, so the modal knows whether to offer the toggle. */
38
+ export declare function hasLogLines(): Promise<boolean>;
39
+ /**
40
+ * dyninfo.txt: the stored diagnostics entries followed by a [Device Info] block holding
41
+ * `deviceInfo`. Returns null only when there is nothing at all to put in it.
42
+ */
43
+ export declare function toDyninfoFile(deviceInfo: string | null): Promise<RenderedFile | null>;
44
+ /** True when any diagnostics entry is waiting, so a submission knows to send dyninfo unasked. */
45
+ export declare function hasDiagnostics(): Promise<boolean>;
@@ -0,0 +1,227 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.1 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ import { warnAlways, Console } from '../core/logger.js';
3
+ import { FEEDBACK_LOG, FEEDBACK_DIAGNOSTICS } from '../core/db.js';
4
+ import { feedbacklog_transactions } from '../core/storage.js';
5
+ import { isExpired } from '../core/state.js';
6
+ import { nowMs } from '../core/utils.js';
7
+
8
+ /**
9
+ * Log lines and diagnostics entries an app records for its next feedback submission.
10
+ *
11
+ * addFeedbackLog() and addDiagnosticsInfo() accumulate entries in the `logs` store; a feedback
12
+ * submission renders them into the files feedback/add carries (feedbacklog.txt and dyninfo.txt)
13
+ * and removes the ones it took with it, so entries added while a submission is in flight survive.
14
+ *
15
+ * This module deliberately depends on core only, never on the modal, so the main entry point can
16
+ * expose the two collection functions without pulling the feedback UI into an app's bundle.
17
+ */
18
+ /** Entries beyond this are dropped oldest-first, so an app that never submits can't grow forever. */
19
+ const MAX_ENTRIES = 1000;
20
+ /** A single message longer than this is truncated rather than stored whole. */
21
+ const MAX_MESSAGE_LENGTH = 10000;
22
+ /** Neither rendered file is sent above this size (the 1.x limit). */
23
+ const MAX_LOG_FILE_SIZE = 2 * 1024 * 1024;
24
+ /** Bursts of addFeedbackLog() calls coalesce into one trim. */
25
+ const TRIM_DELAY_MS = 2000;
26
+ const LOG_FILE_NAME = 'feedbacklog.txt'; // no i18n
27
+ const DYNINFO_FILE_NAME = 'dyninfo.txt'; // no i18n
28
+ // the types the entries are stored under (2.0.0-beta and 1.x said log and diagnostics)
29
+ const LOG = FEEDBACK_LOG;
30
+ const DIAGNOSTICS = FEEDBACK_DIAGNOSTICS;
31
+ let trimScheduled = false;
32
+ /** Drops the oldest entries once the store is over MAX_ENTRIES. */
33
+ function trimStoredLogs() {
34
+ return feedbacklog_transactions.all().then(function (items) {
35
+ const excess = items.length - MAX_ENTRIES;
36
+ if (excess <= 0) {
37
+ return undefined;
38
+ }
39
+ Console.warn('apptics: dropping ' + excess + ' oldest feedback log entries (cap is ' + MAX_ENTRIES + ')'); // no i18n
40
+ return feedbacklog_transactions.remove(items.slice(0, excess));
41
+ });
42
+ }
43
+ /** One trim per burst of adds, so a chatty app pays for one pass over the store, not one per line. */
44
+ function scheduleTrim() {
45
+ if (trimScheduled) {
46
+ return;
47
+ }
48
+ trimScheduled = true;
49
+ setTimeout(function () {
50
+ trimScheduled = false;
51
+ trimStoredLogs();
52
+ }, TRIM_DELAY_MS);
53
+ }
54
+ function store(item) {
55
+ feedbacklog_transactions.add(item);
56
+ scheduleTrim();
57
+ }
58
+ function truncate(text) {
59
+ return text.length > MAX_MESSAGE_LENGTH ? text.slice(0, MAX_MESSAGE_LENGTH) + '…' : text;
60
+ }
61
+ /**
62
+ * Records a timestamped line for the next feedback submission, sent as feedbacklog.txt.
63
+ * Ignores anything that isn't a non-empty string, as 1.x did.
64
+ */
65
+ function addFeedbackLog(message) {
66
+ if (typeof message !== 'string' || message.length === 0) { // no i18n
67
+ return;
68
+ }
69
+ store({ type: LOG, happenedat: nowMs(), message: truncate(message) });
70
+ }
71
+ /**
72
+ * Records a diagnostics key/value under a heading, sent inside dyninfo.txt.
73
+ * Entries sharing a heading are grouped together in the file.
74
+ */
75
+ /** Messages already printed, so a call repeated in a loop says so once. */
76
+ const refusedSaid = {};
77
+ function refuse(message) {
78
+ if (!refusedSaid[message]) {
79
+ refusedSaid[message] = true;
80
+ warnAlways('AppticsFeedback.addDiagnosticsInfo: ' + message + ', so the entry is not recorded'); // no i18n
81
+ }
82
+ }
83
+ /**
84
+ * Records a diagnostics entry, `value` under `key` in the `heading` block of dyninfo.txt. All three
85
+ * are required: an entry without a value says nothing, so it is refused and the console says why.
86
+ * A value of 0 or false is a value.
87
+ */
88
+ function addDiagnosticsInfo(heading, key, value) {
89
+ if (typeof heading !== 'string' || heading.length === 0) { // no i18n
90
+ refuse('a heading is required');
91
+ return;
92
+ }
93
+ if (typeof key !== 'string' || key.length === 0) { // no i18n
94
+ refuse('a key is required');
95
+ return;
96
+ }
97
+ if (value === undefined || value === null || value === '') { // no i18n
98
+ refuse('a value is required for "' + heading + '" / "' + key + '"');
99
+ return;
100
+ }
101
+ store({
102
+ type: DIAGNOSTICS,
103
+ happenedat: nowMs(),
104
+ heading: heading,
105
+ key: key,
106
+ value: truncate(String(value)),
107
+ });
108
+ }
109
+ /** Removes the entries a submission carried, by the ids the rendered files reported. */
110
+ function feedbacklog_transactions_remove(sentIds) {
111
+ return feedbacklog_transactions.remove(sentIds.map(function (id) { return { id: id }; }));
112
+ }
113
+ /** Entries of one type, oldest first, skipping any that have passed batch_request_timeout. */
114
+ function entriesOfType(type) {
115
+ return feedbacklog_transactions.all().then(function (items) {
116
+ return items.filter(function (item) {
117
+ return item.type === type && !isExpired(item.happenedat);
118
+ });
119
+ });
120
+ }
121
+ /** ISO 8601, from the stored time or a 1.x entry's own timestamp string. */
122
+ function stamp(item) {
123
+ if (typeof item.timestamp === 'string' && item.timestamp.length > 0) {
124
+ return item.timestamp; // migrated from 1.x, which stored the ISO string
125
+ }
126
+ return new Date(typeof item.happenedat === 'number' ? item.happenedat : nowMs()).toISOString();
127
+ }
128
+ function ids(items) {
129
+ return items.map(function (item) { return String(item.id); });
130
+ }
131
+ /** `[heading]` blocks of `key: value` lines, in the order the headings first appeared. */
132
+ function groupDiagnostics(items) {
133
+ const order = [];
134
+ const grouped = {};
135
+ items.forEach(function (item) {
136
+ const heading = String(item.heading);
137
+ if (!grouped[heading]) {
138
+ grouped[heading] = [];
139
+ order.push(heading);
140
+ }
141
+ grouped[heading].push(item.key + ': ' + item.value); // no i18n
142
+ });
143
+ return order.map(function (heading) {
144
+ return '[' + heading + ']\n' + grouped[heading].join('\n'); // no i18n
145
+ }).join('\n\n'); // no i18n
146
+ }
147
+ function asFile(name, content, items) {
148
+ const file = new File([content], name, { type: 'text/plain' }); // no i18n
149
+ if (file.size > MAX_LOG_FILE_SIZE) {
150
+ Console.warn('apptics: ' + name + ' is over ' + (MAX_LOG_FILE_SIZE / (1024 * 1024)) + ' MB, not sending it'); // no i18n
151
+ return null;
152
+ }
153
+ return { file: file, ids: ids(items) };
154
+ }
155
+ function renderLogLines(items) {
156
+ return items.map(function (item) {
157
+ return '[' + stamp(item) + '] ' + item.message; // no i18n
158
+ }).join('\n'); // no i18n
159
+ }
160
+ /** feedbacklog.txt from the stored log lines, or null when there are none. */
161
+ function toLogFile() {
162
+ return entriesOfType(LOG).then(function (items) {
163
+ if (items.length === 0) {
164
+ return null;
165
+ }
166
+ return asFile(LOG_FILE_NAME, renderLogLines(items), items);
167
+ });
168
+ }
169
+ /** `16 Oct 2026, 11:53:48 PM IST`: a log line's time in the visitor's own zone, for the viewer. */
170
+ function readableStamp(item) {
171
+ var iso = stamp(item);
172
+ var d = new Date(iso);
173
+ if (isNaN(d.getTime())) {
174
+ return iso;
175
+ }
176
+ return d.toLocaleDateString(undefined, { day: '2-digit', month: 'short', year: 'numeric' }) + ', ' + // no i18n
177
+ d.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit', timeZoneName: 'short' }); // no i18n
178
+ }
179
+ /**
180
+ * The log lines for showing in the modal before sending, each time in the visitor's local zone.
181
+ * The file that is sent (toLogFile) keeps the ISO 8601 UTC stamps, so the server and anything
182
+ * that parses it are unaffected.
183
+ */
184
+ function logText() {
185
+ return entriesOfType(LOG).then(function (items) {
186
+ return items.map(function (item) {
187
+ return '[' + readableStamp(item) + '] ' + item.message; // no i18n
188
+ }).join('\n'); // no i18n
189
+ });
190
+ }
191
+ /** The diagnostics entries as dyninfo.txt would carry them, without the device info block. */
192
+ function diagnosticsText() {
193
+ return entriesOfType(DIAGNOSTICS).then(groupDiagnostics);
194
+ }
195
+ /** True when any log line is waiting, so the modal knows whether to offer the toggle. */
196
+ function hasLogLines() {
197
+ return entriesOfType(LOG).then(function (items) {
198
+ return items.length > 0;
199
+ });
200
+ }
201
+ /**
202
+ * dyninfo.txt: the stored diagnostics entries followed by a [Device Info] block holding
203
+ * `deviceInfo`. Returns null only when there is nothing at all to put in it.
204
+ */
205
+ function toDyninfoFile(deviceInfo) {
206
+ return entriesOfType(DIAGNOSTICS).then(function (items) {
207
+ const blocks = [];
208
+ if (items.length > 0) {
209
+ blocks.push(groupDiagnostics(items));
210
+ }
211
+ if (deviceInfo) {
212
+ blocks.push('[Device Info]\n' + deviceInfo); // no i18n
213
+ }
214
+ if (blocks.length === 0) {
215
+ return null;
216
+ }
217
+ return asFile(DYNINFO_FILE_NAME, blocks.join('\n\n'), items); // no i18n
218
+ });
219
+ }
220
+ /** True when any diagnostics entry is waiting, so a submission knows to send dyninfo unasked. */
221
+ function hasDiagnostics() {
222
+ return entriesOfType(DIAGNOSTICS).then(function (items) {
223
+ return items.length > 0;
224
+ });
225
+ }
226
+
227
+ export { DYNINFO_FILE_NAME, LOG_FILE_NAME, MAX_LOG_FILE_SIZE, addDiagnosticsInfo, addFeedbackLog, diagnosticsText, feedbacklog_transactions_remove, hasDiagnostics, hasLogLines, logText, toDyninfoFile, toLogFile, trimStoredLogs };
@@ -0,0 +1,18 @@
1
+ /** quartz_domain as a recording host: zoho.com → https://quartz.zoho.com. '' when it isn't a domain. */
2
+ export declare function recordingDomain(domain: string): string;
3
+ /**
4
+ * The Quartz script for an app whose getsdkconfig answer carries no quartz_cdn_url, chosen by
5
+ * the serviceUrl: a localzoho server's apps load it from Zoho's local CDN, every other app from
6
+ * the public one.
7
+ */
8
+ export declare function defaultQuartzScriptUrl(serviceUrl: string): string;
9
+ /** The script to load: quartz_cdn_url when getsdkconfig gave one, else the CDN the serviceUrl points to. */
10
+ export declare function quartzScriptSource(cdnUrl: string, serviceUrl: string): string;
11
+ /** The url to load, or '' when it isn't an https url on a Zoho host. */
12
+ export declare function quartzScriptUrl(url: string): string;
13
+ /**
14
+ * Makes Quartz available: resolves true once it is on the page, false when it can't be (no url,
15
+ * a url that isn't allowed, or a script that failed to load). Adds the script once; every caller
16
+ * waits on the same load, and a failed one may be tried again on the next open.
17
+ */
18
+ export declare function loadQuartz(url: string): Promise<boolean>;