@zoho_apptics/apptics-js-sdk 2.0.0-beta → 2.0.0-beta.2

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 (236) hide show
  1. package/CHANGELOG.md +191 -21
  2. package/README.md +519 -333
  3. package/dist/apptics.esm.min.js +2 -2
  4. package/dist/apptics.esm.min.js.map +1 -1
  5. package/dist/apptics.min.js +2 -2
  6. package/dist/apptics.min.js.map +1 -1
  7. package/dist/chunks/lifecycle-C6m1W7jo.min.js +3 -0
  8. package/dist/chunks/lifecycle-C6m1W7jo.min.js.map +1 -0
  9. package/dist/chunks/send-CgUO82ne.min.js +3 -0
  10. package/dist/chunks/send-CgUO82ne.min.js.map +1 -0
  11. package/dist/cjs/core/attempts.js +1 -1
  12. package/dist/cjs/core/batch.js +2 -2
  13. package/dist/cjs/core/consent.d.ts +18 -4
  14. package/dist/cjs/core/consent.js +31 -15
  15. package/dist/cjs/core/constants.d.ts +57 -27
  16. package/dist/cjs/core/constants.js +52 -33
  17. package/dist/cjs/core/db.d.ts +12 -4
  18. package/dist/cjs/core/db.js +167 -34
  19. package/dist/cjs/core/debug.js +1 -1
  20. package/dist/cjs/core/env.d.ts +0 -3
  21. package/dist/cjs/core/env.js +1 -9
  22. package/dist/cjs/core/framework-id.d.ts +1 -1
  23. package/dist/cjs/core/framework-id.js +3 -3
  24. package/dist/cjs/core/guard.d.ts +9 -0
  25. package/dist/cjs/core/guard.js +27 -13
  26. package/dist/cjs/core/hooks.d.ts +7 -4
  27. package/dist/cjs/core/hooks.js +3 -3
  28. package/dist/cjs/core/locks.d.ts +9 -0
  29. package/dist/cjs/core/locks.js +22 -0
  30. package/dist/cjs/core/logger.d.ts +3 -4
  31. package/dist/cjs/core/logger.js +4 -40
  32. package/dist/cjs/core/state.d.ts +9 -6
  33. package/dist/cjs/core/state.js +3 -5
  34. package/dist/cjs/core/storage.d.ts +20 -5
  35. package/dist/cjs/core/storage.js +115 -20
  36. package/dist/cjs/core/stylesheet.d.ts +8 -0
  37. package/dist/cjs/core/stylesheet.js +29 -0
  38. package/dist/cjs/core/transport.d.ts +2 -0
  39. package/dist/cjs/core/transport.js +30 -18
  40. package/dist/cjs/core/utils.js +1 -1
  41. package/dist/cjs/core/validate.js +2 -2
  42. package/dist/cjs/device/appversion.d.ts +10 -6
  43. package/dist/cjs/device/appversion.js +38 -3
  44. package/dist/cjs/device/index.d.ts +28 -2
  45. package/dist/cjs/device/index.js +312 -44
  46. package/dist/cjs/engagement/api-rules.d.ts +32 -67
  47. package/dist/cjs/engagement/api-rules.js +144 -157
  48. package/dist/cjs/engagement/auto-api.js +2 -2
  49. package/dist/cjs/engagement/auto-screen.d.ts +2 -0
  50. package/dist/cjs/engagement/auto-screen.js +67 -3
  51. package/dist/cjs/engagement/defined-events.js +1 -1
  52. package/dist/cjs/engagement/send.js +12 -3
  53. package/dist/cjs/engagement/session.d.ts +29 -3
  54. package/dist/cjs/engagement/session.js +253 -26
  55. package/dist/cjs/engagement/track.d.ts +4 -4
  56. package/dist/cjs/engagement/track.js +58 -30
  57. package/dist/cjs/errors/send.js +2 -2
  58. package/dist/cjs/errors/track.d.ts +2 -1
  59. package/dist/cjs/errors/track.js +49 -7
  60. package/dist/cjs/feedback/controls.d.ts +12 -0
  61. package/dist/cjs/feedback/controls.js +104 -25
  62. package/dist/cjs/feedback/index.d.ts +8 -7
  63. package/dist/cjs/feedback/index.js +32 -13
  64. package/dist/cjs/feedback/logs.d.ts +13 -11
  65. package/dist/cjs/feedback/logs.js +57 -28
  66. package/dist/cjs/feedback/quartz.d.ts +18 -0
  67. package/dist/cjs/feedback/quartz.js +105 -0
  68. package/dist/cjs/feedback/send.d.ts +5 -2
  69. package/dist/cjs/feedback/send.js +30 -28
  70. package/dist/cjs/feedback/styles.d.ts +10 -0
  71. package/dist/cjs/feedback/styles.js +8 -0
  72. package/dist/cjs/feedback/template.d.ts +1 -1
  73. package/dist/cjs/feedback/template.js +20 -12
  74. package/dist/cjs/feedback/ui.d.ts +21 -6
  75. package/dist/cjs/feedback/ui.js +283 -70
  76. package/dist/cjs/heatmap/send.d.ts +2 -0
  77. package/dist/cjs/heatmap/send.js +3 -5
  78. package/dist/cjs/heatmap/track.d.ts +1 -1
  79. package/dist/cjs/heatmap/track.js +87 -16
  80. package/dist/cjs/index.d.ts +16 -63
  81. package/dist/cjs/index.js +144 -95
  82. package/dist/cjs/lifecycle.d.ts +21 -3
  83. package/dist/cjs/lifecycle.js +353 -89
  84. package/dist/cjs/remoteconfig/country.d.ts +4 -0
  85. package/dist/cjs/remoteconfig/country.js +73 -0
  86. package/dist/cjs/remoteconfig/custom.d.ts +7 -7
  87. package/dist/cjs/remoteconfig/custom.js +31 -51
  88. package/dist/cjs/remoteconfig/evaluate.d.ts +3 -3
  89. package/dist/cjs/remoteconfig/evaluate.js +56 -43
  90. package/dist/cjs/remoteconfig/fetch.d.ts +16 -9
  91. package/dist/cjs/remoteconfig/fetch.js +120 -39
  92. package/dist/cjs/remoteconfig/index.d.ts +19 -8
  93. package/dist/cjs/remoteconfig/index.js +81 -39
  94. package/dist/cjs/remoteconfig/store.d.ts +15 -7
  95. package/dist/cjs/remoteconfig/store.js +68 -35
  96. package/dist/cjs/remoteconfig/tz-countries.d.ts +8 -0
  97. package/dist/cjs/remoteconfig/tz-countries.js +13 -0
  98. package/dist/{esm/core → cjs/remotelog}/callsite.d.ts +11 -4
  99. package/dist/cjs/{core → remotelog}/callsite.js +30 -7
  100. package/dist/cjs/remotelog/gate.d.ts +2 -11
  101. package/dist/cjs/remotelog/gate.js +9 -35
  102. package/dist/cjs/remotelog/index.d.ts +4 -21
  103. package/dist/cjs/remotelog/logger.d.ts +11 -17
  104. package/dist/cjs/remotelog/logger.js +31 -59
  105. package/dist/cjs/remotelog/send.js +11 -11
  106. package/dist/cjs/remotelogger/index.d.ts +12 -0
  107. package/dist/cjs/remotelogger/index.js +18 -0
  108. package/dist/cjs/scheduler.d.ts +3 -1
  109. package/dist/cjs/scheduler.js +25 -22
  110. package/dist/cjs/types.d.ts +208 -90
  111. package/dist/cjs/user/index.js +16 -7
  112. package/dist/esm/core/attempts.js +1 -1
  113. package/dist/esm/core/batch.js +2 -2
  114. package/dist/esm/core/consent.d.ts +18 -4
  115. package/dist/esm/core/consent.js +32 -17
  116. package/dist/esm/core/constants.d.ts +57 -27
  117. package/dist/esm/core/constants.js +51 -33
  118. package/dist/esm/core/db.d.ts +12 -4
  119. package/dist/esm/core/db.js +164 -35
  120. package/dist/esm/core/debug.js +1 -1
  121. package/dist/esm/core/env.d.ts +0 -3
  122. package/dist/esm/core/env.js +2 -9
  123. package/dist/esm/core/framework-id.d.ts +1 -1
  124. package/dist/esm/core/framework-id.js +3 -3
  125. package/dist/esm/core/guard.d.ts +9 -0
  126. package/dist/esm/core/guard.js +27 -14
  127. package/dist/esm/core/hooks.d.ts +7 -4
  128. package/dist/esm/core/hooks.js +3 -3
  129. package/dist/esm/core/locks.d.ts +9 -0
  130. package/dist/esm/core/locks.js +20 -0
  131. package/dist/esm/core/logger.d.ts +3 -4
  132. package/dist/esm/core/logger.js +4 -40
  133. package/dist/esm/core/state.d.ts +9 -6
  134. package/dist/esm/core/state.js +3 -5
  135. package/dist/esm/core/storage.d.ts +20 -5
  136. package/dist/esm/core/storage.js +113 -21
  137. package/dist/esm/core/stylesheet.d.ts +8 -0
  138. package/dist/esm/core/stylesheet.js +27 -0
  139. package/dist/esm/core/transport.d.ts +2 -0
  140. package/dist/esm/core/transport.js +30 -19
  141. package/dist/esm/core/utils.js +1 -1
  142. package/dist/esm/core/validate.js +2 -2
  143. package/dist/esm/device/appversion.d.ts +10 -6
  144. package/dist/esm/device/appversion.js +37 -4
  145. package/dist/esm/device/index.d.ts +28 -2
  146. package/dist/esm/device/index.js +313 -49
  147. package/dist/esm/engagement/api-rules.d.ts +32 -67
  148. package/dist/esm/engagement/api-rules.js +143 -155
  149. package/dist/esm/engagement/auto-api.js +3 -3
  150. package/dist/esm/engagement/auto-screen.d.ts +2 -0
  151. package/dist/esm/engagement/auto-screen.js +67 -4
  152. package/dist/esm/engagement/defined-events.js +1 -1
  153. package/dist/esm/engagement/send.js +12 -3
  154. package/dist/esm/engagement/session.d.ts +29 -3
  155. package/dist/esm/engagement/session.js +251 -30
  156. package/dist/esm/engagement/track.d.ts +4 -4
  157. package/dist/esm/engagement/track.js +65 -37
  158. package/dist/esm/errors/send.js +2 -2
  159. package/dist/esm/errors/track.d.ts +2 -1
  160. package/dist/esm/errors/track.js +49 -7
  161. package/dist/esm/feedback/controls.d.ts +12 -0
  162. package/dist/esm/feedback/controls.js +103 -26
  163. package/dist/esm/feedback/index.d.ts +8 -7
  164. package/dist/esm/feedback/index.js +34 -13
  165. package/dist/esm/feedback/logs.d.ts +13 -11
  166. package/dist/esm/feedback/logs.js +59 -30
  167. package/dist/esm/feedback/quartz.d.ts +18 -0
  168. package/dist/esm/feedback/quartz.js +99 -0
  169. package/dist/esm/feedback/send.d.ts +5 -2
  170. package/dist/esm/feedback/send.js +31 -31
  171. package/dist/esm/feedback/styles.d.ts +10 -0
  172. package/dist/esm/feedback/styles.js +4 -0
  173. package/dist/esm/feedback/template.d.ts +1 -1
  174. package/dist/esm/feedback/template.js +20 -12
  175. package/dist/esm/feedback/ui.d.ts +21 -6
  176. package/dist/esm/feedback/ui.js +283 -71
  177. package/dist/esm/heatmap/send.d.ts +2 -0
  178. package/dist/esm/heatmap/send.js +3 -5
  179. package/dist/esm/heatmap/track.d.ts +1 -1
  180. package/dist/esm/heatmap/track.js +87 -16
  181. package/dist/esm/index.d.ts +16 -63
  182. package/dist/esm/index.js +148 -83
  183. package/dist/esm/lifecycle.d.ts +21 -3
  184. package/dist/esm/lifecycle.js +359 -98
  185. package/dist/esm/remoteconfig/country.d.ts +4 -0
  186. package/dist/esm/remoteconfig/country.js +70 -0
  187. package/dist/esm/remoteconfig/custom.d.ts +7 -7
  188. package/dist/esm/remoteconfig/custom.js +32 -52
  189. package/dist/esm/remoteconfig/evaluate.d.ts +3 -3
  190. package/dist/esm/remoteconfig/evaluate.js +57 -44
  191. package/dist/esm/remoteconfig/fetch.d.ts +16 -9
  192. package/dist/esm/remoteconfig/fetch.js +120 -39
  193. package/dist/esm/remoteconfig/index.d.ts +19 -8
  194. package/dist/esm/remoteconfig/index.js +82 -40
  195. package/dist/esm/remoteconfig/store.d.ts +15 -7
  196. package/dist/esm/remoteconfig/store.js +68 -36
  197. package/dist/esm/remoteconfig/tz-countries.d.ts +8 -0
  198. package/dist/esm/remoteconfig/tz-countries.js +11 -0
  199. package/dist/{cjs/core → esm/remotelog}/callsite.d.ts +11 -4
  200. package/dist/esm/{core → remotelog}/callsite.js +30 -8
  201. package/dist/esm/remotelog/gate.d.ts +2 -11
  202. package/dist/esm/remotelog/gate.js +10 -32
  203. package/dist/esm/remotelog/index.d.ts +4 -21
  204. package/dist/esm/remotelog/logger.d.ts +11 -17
  205. package/dist/esm/remotelog/logger.js +33 -61
  206. package/dist/esm/remotelog/send.js +13 -13
  207. package/dist/esm/remotelogger/index.d.ts +12 -0
  208. package/dist/esm/remotelogger/index.js +13 -0
  209. package/dist/esm/scheduler.d.ts +3 -1
  210. package/dist/esm/scheduler.js +26 -24
  211. package/dist/esm/types.d.ts +208 -90
  212. package/dist/esm/user/index.js +18 -8
  213. package/dist/feedback.esm.min.js +2 -2
  214. package/dist/feedback.esm.min.js.map +1 -1
  215. package/dist/remoteconfig.esm.min.js +3 -0
  216. package/dist/remoteconfig.esm.min.js.map +1 -0
  217. package/dist/remotelogger.esm.min.js +3 -0
  218. package/dist/remotelogger.esm.min.js.map +1 -0
  219. package/package.json +16 -17
  220. package/dist/chunks/batch-BU_mTpm1.min.js +0 -3
  221. package/dist/chunks/batch-BU_mTpm1.min.js.map +0 -1
  222. package/dist/chunks/logs-Bea5zUW_.min.js +0 -3
  223. package/dist/chunks/logs-Bea5zUW_.min.js.map +0 -1
  224. package/dist/cjs/auto-init.d.ts +0 -8
  225. package/dist/cjs/auto-init.js +0 -32
  226. package/dist/cjs/heatmap/index.d.ts +0 -16
  227. package/dist/cjs/heatmap/index.js +0 -22
  228. package/dist/cjs/remotelog/index.js +0 -55
  229. package/dist/esm/auto-init.d.ts +0 -8
  230. package/dist/esm/auto-init.js +0 -29
  231. package/dist/esm/heatmap/index.d.ts +0 -16
  232. package/dist/esm/heatmap/index.js +0 -17
  233. package/dist/esm/remotelog/index.js +0 -51
  234. package/dist/heatmap.esm.min.js +0 -3
  235. package/dist/heatmap.esm.min.js.map +0 -1
  236. package/dist/style.css +0 -1
@@ -1,26 +1,73 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var logger = require('./logger.js');
5
5
  var utils = require('./utils.js');
6
6
 
7
7
  const DB_NAME = 'apptics'; // no i18n
8
- // 3 added the heatmaps store. The upgrade only creates stores that are missing, so an existing
9
- // database keeps everything already queued in it.
10
- const DB_VERSION = 3;
8
+ // 3 added the heatmaps store. 4 renamed: each record's order key `seq` to `queue`, the logs store
9
+ // to feedbacklogs and consolelogs to remotelogs. Every upgrade keeps what is already queued.
10
+ const DB_VERSION = 4;
11
11
  const OPEN_TIMEOUT_MS = 3000;
12
- const QUEUES = ['engagements', 'errors', 'logs', 'consolelogs', 'heatmaps']; // no i18n
13
- /** 1.x localStorage keys; also the layout of the localStorage backend. */
12
+ const QUEUES = ['engagements', 'errors', 'feedbacklogs', 'remotelogs', 'heatmaps']; // no i18n
13
+ /** The field, and the index on it, that keeps a queue's records in the order they were added. */
14
+ const QUEUE_KEY = 'queue'; // no i18n
15
+ /** Version 3's names, which the version 4 upgrade moves to the ones above. */
16
+ const OLD_QUEUE_KEY = 'seq'; // no i18n
17
+ const RENAMED_STORES = [['logs', 'feedbacklogs'], ['consolelogs', 'remotelogs']]; // no i18n
18
+ /** The types a feedback entry is stored under: an addFeedbackLog() line, an addDiagnosticsInfo() entry. */
19
+ const FEEDBACK_LOG = 'feedbacklog'; // no i18n
20
+ const FEEDBACK_DIAGNOSTICS = 'feedbackdiagnostics'; // no i18n
21
+ const OLD_FEEDBACK_TYPES = Object.freeze({
22
+ log: FEEDBACK_LOG, // no i18n
23
+ diagnostics: FEEDBACK_DIAGNOSTICS, // no i18n
24
+ });
25
+ /** A feedback entry from 1.x or 2.0.0-beta, with the type it is stored under now. */
26
+ function renameFeedbackType(item) {
27
+ var renamed = item && typeof item.type === 'string' ? OLD_FEEDBACK_TYPES[item.type] : undefined; // no i18n
28
+ return renamed ? { ...item, type: renamed } : item;
29
+ }
30
+ /** 1.x localStorage keys, read once to bring 1.x data into IndexedDB (see migrateLegacy). */
14
31
  const LEGACY_KEYS = Object.freeze({
15
32
  settings: 'apptics-device-info', // no i18n
16
33
  engagements: 'apptics-engagements-transactions', // no i18n
17
34
  errors: 'apptics-errors-transactions', // no i18n
18
35
  logs: 'apptics-log-transactions', // no i18n
19
36
  consolelogs: 'apptics-consolelog-transactions', // no i18n
20
- // not a 1.x key: heatmaps did not exist then. It is here because this map is also the
21
- // localStorage backend's layout, so the store needs a name there too
37
+ });
38
+ /** The localStorage backend's layout, for a browser where IndexedDB will not open. */
39
+ const LOCAL_KEYS = Object.freeze({
40
+ settings: LEGACY_KEYS.settings,
41
+ engagements: LEGACY_KEYS.engagements,
42
+ errors: LEGACY_KEYS.errors,
43
+ feedbacklogs: 'apptics-feedbacklog-transactions', // no i18n
44
+ remotelogs: 'apptics-remotelog-transactions', // no i18n
22
45
  heatmaps: 'apptics-heatmap-transactions', // no i18n
23
46
  });
47
+ /**
48
+ * The localStorage backend once kept these two under the 1.x keys. Moved to the new ones on first
49
+ * use, feedback types renamed on the way, unless something is already there.
50
+ */
51
+ function moveRenamedLocalKeys() {
52
+ [[LEGACY_KEYS.logs, LOCAL_KEYS.feedbacklogs], [LEGACY_KEYS.consolelogs, LOCAL_KEYS.remotelogs]].forEach(function (pair) {
53
+ try {
54
+ var from = pair[0];
55
+ var to = pair[1];
56
+ var old = localStorage.getItem(from);
57
+ if (old === null) {
58
+ return;
59
+ }
60
+ if (localStorage.getItem(to) === null) {
61
+ var items = asList(JSON.parse(old));
62
+ localStorage.setItem(to, JSON.stringify(to === LOCAL_KEYS.feedbacklogs ? items.map(renameFeedbackType) : items));
63
+ }
64
+ localStorage.removeItem(from);
65
+ }
66
+ catch (err) {
67
+ // left where it is; the next load tries again
68
+ }
69
+ });
70
+ }
24
71
  /** Shape guards shared by both backends and the 1.x migration. */
25
72
  function asList(value) {
26
73
  return Array.isArray(value) ? value : [];
@@ -48,26 +95,33 @@ function writeJSON(key, value) {
48
95
  }
49
96
  }
50
97
  function createLocalStorageBackend() {
98
+ moveRenamedLocalKeys();
51
99
  return {
52
100
  kind: 'localstorage', // no i18n
53
101
  loadSettings() {
54
- return Promise.resolve(asDict(readJSON(LEGACY_KEYS.settings)));
102
+ return Promise.resolve(asDict(readJSON(LOCAL_KEYS.settings)));
55
103
  },
56
104
  putSetting(key, value) {
57
- const all = asDict(readJSON(LEGACY_KEYS.settings));
105
+ const all = asDict(readJSON(LOCAL_KEYS.settings));
58
106
  all[key] = value;
59
- writeJSON(LEGACY_KEYS.settings, all);
107
+ writeJSON(LOCAL_KEYS.settings, all);
108
+ return Promise.resolve();
109
+ },
110
+ deleteSetting(key) {
111
+ const all = asDict(readJSON(LOCAL_KEYS.settings));
112
+ delete all[key];
113
+ writeJSON(LOCAL_KEYS.settings, all);
60
114
  return Promise.resolve();
61
115
  },
62
116
  clearSettings() {
63
- writeJSON(LEGACY_KEYS.settings, {});
117
+ writeJSON(LOCAL_KEYS.settings, {});
64
118
  return Promise.resolve();
65
119
  },
66
120
  queueAll(store) {
67
- return Promise.resolve(asList(readJSON(LEGACY_KEYS[store])));
121
+ return Promise.resolve(asList(readJSON(LOCAL_KEYS[store])));
68
122
  },
69
123
  queuePut(store, items) {
70
- const list = asList(readJSON(LEGACY_KEYS[store]));
124
+ const list = asList(readJSON(LOCAL_KEYS[store]));
71
125
  items.forEach(function (item) {
72
126
  const index = list.findIndex(function (existing) { return existing.id === item.id; });
73
127
  if (index === -1) {
@@ -77,32 +131,32 @@ function createLocalStorageBackend() {
77
131
  list[index] = item;
78
132
  }
79
133
  });
80
- writeJSON(LEGACY_KEYS[store], list);
134
+ writeJSON(LOCAL_KEYS[store], list);
81
135
  return Promise.resolve();
82
136
  },
83
137
  queueDelete(store, ids) {
84
- const remaining = asList(readJSON(LEGACY_KEYS[store])).filter(function (item) {
138
+ const remaining = asList(readJSON(LOCAL_KEYS[store])).filter(function (item) {
85
139
  return ids.indexOf(item.id) === -1;
86
140
  });
87
- writeJSON(LEGACY_KEYS[store], remaining);
141
+ writeJSON(LOCAL_KEYS[store], remaining);
88
142
  return Promise.resolve();
89
143
  },
90
144
  queueClear(store) {
91
- writeJSON(LEGACY_KEYS[store], []);
145
+ writeJSON(LOCAL_KEYS[store], []);
92
146
  return Promise.resolve();
93
147
  },
94
148
  };
95
149
  }
96
- let lastSeq = 0;
150
+ let lastQueue = 0;
97
151
  /**
98
152
  * Strictly increasing, and time-based so tabs interleave in roughly the right order.
99
153
  * Counting up from the last value rather than a counter that wraps keeps insertion order
100
154
  * even when a chatty caller adds more than a thousand items inside one millisecond.
101
155
  */
102
- function nextSeq() {
156
+ function nextQueue() {
103
157
  const base = utils.nowMs() * 1000;
104
- lastSeq = base > lastSeq ? base : lastSeq + 1;
105
- return lastSeq;
158
+ lastQueue = base > lastQueue ? base : lastQueue + 1;
159
+ return lastQueue;
106
160
  }
107
161
  function request(req) {
108
162
  return new Promise(function (resolve, reject) {
@@ -117,7 +171,21 @@ function completed(tx) {
117
171
  tx.onabort = function () { reject(tx.error); };
118
172
  });
119
173
  }
120
- /** Puts `item` unless it exists (keepExisting) or replaces it keeping its seq. Runs inside `store`'s transaction. */
174
+ /**
175
+ * The record's `type` for an item with none of its own: heatmap records carry no type, since
176
+ * their payload is the item itself and the server takes no extra field. Never undefined.
177
+ */
178
+ const STORE_TYPES = Object.freeze({
179
+ engagements: 'engagement', // no i18n
180
+ errors: 'error', // no i18n
181
+ feedbacklogs: FEEDBACK_LOG,
182
+ remotelogs: 'remotelog', // no i18n
183
+ heatmaps: 'heatmap', // no i18n
184
+ });
185
+ function recordType(storeName, item) {
186
+ return item && typeof item.type === 'string' && item.type !== '' ? item.type : (STORE_TYPES[storeName] || storeName); // no i18n
187
+ }
188
+ /** Puts `item` unless it exists (keepExisting) or replaces it keeping its place. Runs inside `store`'s transaction. */
121
189
  function putRecord(store, item, keepExisting) {
122
190
  const id = String(item.id);
123
191
  const lookup = store.get(id);
@@ -126,7 +194,7 @@ function putRecord(store, item, keepExisting) {
126
194
  if (existing && keepExisting) {
127
195
  return;
128
196
  }
129
- store.put({ id: id, seq: existing ? existing.seq : nextSeq(), type: item.type, item: item });
197
+ store.put({ id: id, queue: existing ? existing.queue : nextQueue(), type: recordType(store.name, item), item: item });
130
198
  };
131
199
  }
132
200
  /** Our stores, as created by onupgradeneeded. */
@@ -187,15 +255,7 @@ function openOnce(factory, timeoutMs) {
187
255
  return;
188
256
  }
189
257
  req.onupgradeneeded = function () {
190
- const db = req.result;
191
- if (!db.objectStoreNames.contains('settings')) { // no i18n
192
- db.createObjectStore('settings'); // no i18n
193
- }
194
- QUEUES.forEach(function (name) {
195
- if (!db.objectStoreNames.contains(name)) {
196
- db.createObjectStore(name, { keyPath: 'id' }).createIndex('seq', 'seq'); // no i18n
197
- }
198
- });
258
+ upgrade(req.result, req.transaction);
199
259
  };
200
260
  req.onsuccess = function () {
201
261
  if (settled) {
@@ -226,6 +286,70 @@ function openOnce(factory, timeoutMs) {
226
286
  };
227
287
  });
228
288
  }
289
+ /**
290
+ * Creates what is missing and moves version 3's data to version 4's names, inside the upgrade's
291
+ * own transaction: either the whole upgrade lands, or the database stays at the old version with
292
+ * everything still in it.
293
+ */
294
+ function upgrade(db, tx) {
295
+ if (!db.objectStoreNames.contains('settings')) { // no i18n
296
+ db.createObjectStore('settings'); // no i18n
297
+ }
298
+ QUEUES.forEach(function (name) {
299
+ if (!db.objectStoreNames.contains(name)) {
300
+ db.createObjectStore(name, { keyPath: 'id' }).createIndex(QUEUE_KEY, QUEUE_KEY); // no i18n
301
+ }
302
+ });
303
+ // kept stores: the order key is renamed on every record, and the index with it
304
+ QUEUES.forEach(function (name) {
305
+ const store = tx.objectStore(name);
306
+ if (!store.indexNames.contains(OLD_QUEUE_KEY)) {
307
+ return;
308
+ }
309
+ store.deleteIndex(OLD_QUEUE_KEY);
310
+ if (!store.indexNames.contains(QUEUE_KEY)) {
311
+ store.createIndex(QUEUE_KEY, QUEUE_KEY);
312
+ }
313
+ eachRecord(store, function (record, cursor) {
314
+ cursor.update(renamedRecord(record, false, name));
315
+ });
316
+ });
317
+ // renamed stores: every record moves to its new store, then the old store goes
318
+ RENAMED_STORES.forEach(function (pair) {
319
+ const from = pair[0];
320
+ const to = pair[1];
321
+ if (!db.objectStoreNames.contains(from)) {
322
+ return;
323
+ }
324
+ const source = tx.objectStore(from);
325
+ const target = tx.objectStore(to);
326
+ eachRecord(source, function (record) {
327
+ target.put(renamedRecord(record, to === 'feedbacklogs', to)); // no i18n
328
+ }, function () {
329
+ db.deleteObjectStore(from);
330
+ });
331
+ });
332
+ }
333
+ /** Calls `each` for every record of `store`, then `done`, inside the transaction `store` is in. */
334
+ function eachRecord(store, each, done) {
335
+ const req = store.openCursor();
336
+ req.onsuccess = function () {
337
+ const cursor = req.result;
338
+ if (!cursor) {
339
+ if (done)
340
+ done();
341
+ return;
342
+ }
343
+ each(cursor.value, cursor);
344
+ cursor.continue();
345
+ };
346
+ }
347
+ /** A version 3 record under version 4's names: `queue` for `seq`, and the feedback types renamed. */
348
+ function renamedRecord(record, feedback, storeName) {
349
+ const queue = typeof record[QUEUE_KEY] === 'number' ? record[QUEUE_KEY] : (typeof record[OLD_QUEUE_KEY] === 'number' ? record[OLD_QUEUE_KEY] : nextQueue()); // no i18n
350
+ const item = (feedback ? renameFeedbackType(record.item) : record.item);
351
+ return { id: String(record.id), queue: queue, type: recordType(storeName, item), item: item };
352
+ }
229
353
  function createIndexedDBBackend(db) {
230
354
  return {
231
355
  kind: 'indexeddb', // no i18n
@@ -244,13 +368,18 @@ function createIndexedDBBackend(db) {
244
368
  tx.objectStore('settings').put(value, key); // no i18n
245
369
  return completed(tx);
246
370
  },
371
+ deleteSetting(key) {
372
+ const tx = db.transaction('settings', 'readwrite'); // no i18n
373
+ tx.objectStore('settings').delete(key); // no i18n
374
+ return completed(tx);
375
+ },
247
376
  clearSettings() {
248
377
  const tx = db.transaction('settings', 'readwrite'); // no i18n
249
378
  tx.objectStore('settings').clear(); // no i18n
250
379
  return completed(tx);
251
380
  },
252
381
  queueAll(store) {
253
- const index = db.transaction(store, 'readonly').objectStore(store).index('seq'); // no i18n
382
+ const index = db.transaction(store, 'readonly').objectStore(store).index(QUEUE_KEY);
254
383
  return request(index.getAll()).then(function (records) {
255
384
  return records.map(function (record) { return record.item; });
256
385
  });
@@ -325,10 +454,14 @@ function openBackend() {
325
454
 
326
455
  exports.DB_NAME = DB_NAME;
327
456
  exports.DB_VERSION = DB_VERSION;
457
+ exports.FEEDBACK_DIAGNOSTICS = FEEDBACK_DIAGNOSTICS;
458
+ exports.FEEDBACK_LOG = FEEDBACK_LOG;
328
459
  exports.LEGACY_KEYS = LEGACY_KEYS;
460
+ exports.LOCAL_KEYS = LOCAL_KEYS;
329
461
  exports.asDict = asDict;
330
462
  exports.asList = asList;
331
463
  exports.createIndexedDBBackend = createIndexedDBBackend;
332
464
  exports.createLocalStorageBackend = createLocalStorageBackend;
333
465
  exports.openBackend = openBackend;
334
466
  exports.openIndexedDB = openIndexedDB;
467
+ exports.renameFeedbackType = renameFeedbackType;
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var constants = require('./constants.js');
@@ -1,4 +1,3 @@
1
- import type { AppticsConfig } from '../types.js';
2
1
  export declare function isBlockedWS(ua: string): boolean;
3
2
  /** Device RAM as the API wants it ("4 GB"). Chromium only; empty elsewhere. */
4
3
  export declare function getRam(): string;
@@ -24,5 +23,3 @@ export declare function getTimeZone(): string;
24
23
  export declare function is_apptics_disabled(): boolean;
25
24
  /** Pure DNT check (no side effects). consent.hasDoNotTrackEnabled() applies NO_TRACKING. */
26
25
  export declare function isDntOn(): boolean;
27
- /** The console snippet's config (window.appticssettings._defaultoptions), if the page defines one. */
28
- export declare function getSnippetOptions(): AppticsConfig | undefined;
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var constants = require('./constants.js');
@@ -242,13 +242,6 @@ function isDntOn() {
242
242
  return utils.includes(dntValues, dntValue);
243
243
  });
244
244
  }
245
- /** The console snippet's config (window.appticssettings._defaultoptions), if the page defines one. */
246
- function getSnippetOptions() {
247
- if (typeof window === 'undefined' || !window.appticssettings) { // no i18n
248
- return undefined;
249
- }
250
- return window.appticssettings._defaultoptions;
251
- }
252
245
 
253
246
  exports.getBatteryPercent = getBatteryPercent;
254
247
  exports.getBrowser = getBrowser;
@@ -260,7 +253,6 @@ exports.getOS = getOS;
260
253
  exports.getOrientation = getOrientation;
261
254
  exports.getRam = getRam;
262
255
  exports.getReferringURL = getReferringURL;
263
- exports.getSnippetOptions = getSnippetOptions;
264
256
  exports.getTimeZone = getTimeZone;
265
257
  exports.isBlockedWS = isBlockedWS;
266
258
  exports.isDntOn = isDntOn;
@@ -1 +1 @@
1
- export declare const FRAMEWORK_ID = 5996;
1
+ export declare const FRAMEWORK_ID = 6003;
@@ -1,9 +1,9 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  // Generated by scripts/register-version.mjs — do not edit by hand.
5
5
  // The framework id Apptics issued for this SDK, from POST /sdk/web/v1/framework/addversion
6
- // (version 2.0.0-beta, platform Browser). Regenerated on every npm pack.
7
- const FRAMEWORK_ID = 5996;
6
+ // (version 2.0.0-beta.2, platform Browser). Regenerated on every npm pack.
7
+ const FRAMEWORK_ID = 6003;
8
8
 
9
9
  exports.FRAMEWORK_ID = FRAMEWORK_ID;
@@ -1,2 +1,11 @@
1
1
  /** Public calls never throw into the host app, and are buffered until start-up finishes. */
2
2
  export declare function guard<F extends (...args: any[]) => any>(name: string, fn: F): F;
3
+ /**
4
+ * Hands a public call's own `arguments` to its guarded function, exactly as they were given.
5
+ *
6
+ * guard() returns a wrapper that takes `...args`, so a browser console shows every public call as
7
+ * `(...args)`. Each public call is therefore its own function with named parameters, which is what
8
+ * the console shows, and forwards through this: `arguments` rather than the named parameters, so
9
+ * a call keeps its argument count (addEvent tells its two forms apart by it).
10
+ */
11
+ export declare function forward<F extends (...args: any[]) => any>(guarded: F, args: IArguments): ReturnType<F>;
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var state = require('./state.js');
@@ -10,29 +10,31 @@ var logger = require('./logger.js');
10
10
  * The two log collectors run now so an entry keeps the time it actually happened.
11
11
  */
12
12
  const RUN_BEFORE_READY = {
13
- 'Apptics.init': true, ready: true, reset: true, getUser: true, getTrackingStatus: true, sendFeedback: true,
14
- addFeedbackLog: true, addDiagnosticsInfo: true,
15
- // a switch, so it takes effect in order with the lines logged after it
16
- 'AppticsLogger.enable': true, 'AppticsLogger.disable': true, 'AppticsLogger.isEnabled': true,
13
+ 'Apptics.init': true, 'Apptics.ready': true, 'Apptics.reset': true, 'AppticsUser.getUser': true,
14
+ 'AppticsSettings.getTrackingStatus': true, 'AppticsFeedback.sendFeedback': true,
15
+ 'AppticsFeedback.addFeedbackLog': true, 'AppticsFeedback.addDiagnosticsInfo': true,
16
+ // a switch, which init() must not undo: it keeps what was set when its config has no theme
17
+ 'AppticsFeedback.setFeedbackTheme': true,
17
18
  // a switch, and a call that hands back the id endTrackApi needs: neither can wait in a queue
18
- 'AppticsApiTracker.configure': true, 'AppticsApiTracker.startTrackApi': true,
19
+ 'AppticsApi.configure': true, 'AppticsApi.startTrackApi': true,
19
20
  // these wait for ready() themselves, and a queued call would hand back undefined, not a Promise
20
21
  'AppticsRemoteConfig.fetchValue': true, 'AppticsRemoteConfig.fetchValues': true,
21
- 'AppticsRemoteConfig.setFallbackWithOfflineValue': true, 'AppticsRemoteConfig.setCustomConditionValue': true,
22
- enableDebug: true, disableDebug: true,
22
+ 'AppticsRemoteConfig.setCustomConditionValue': true,
23
+ 'Apptics.enableDebug': true, 'Apptics.disableDebug': true,
23
24
  };
24
25
  /**
25
26
  * Calls that record or send something, and so are lost when the SDK hasn't started. Calls that only
26
- * set a switch or read a value (enableDebug, AppticsLogger.enable, addFeedbackLog, getUser, …)
27
+ * set a switch or read a value (Apptics.enableDebug, AppticsLogger.enable, AppticsFeedback.addFeedbackLog,
28
+ * AppticsUser.getUser, …)
27
29
  * work without Apptics.init() and are not listed.
28
30
  */
29
31
  const NEEDS_INIT = {
30
- 'AppticsEvents.addEvent': true, 'AppticsScreenTracker.inScreen': true, 'AppticsScreenTracker.outScreen': true,
31
- 'AppticsApiTracker.endTrackApi': true, AppticsTrackError: true, AppticsSetUser: true, flush: true,
32
- AppticsLogger: true, sendFeedback: true, 'AppticsRemoteConfig.fetchValue': true,
32
+ 'AppticsEvent.addEvent': true, 'AppticsScreen.inScreen': true, 'AppticsScreen.outScreen': true,
33
+ 'AppticsApi.endTrackApi': true, 'AppticsError.trackError': true, 'AppticsUser.setUser': true,
34
+ 'Apptics.flush': true, AppticsLogger: true, 'AppticsFeedback.sendFeedback': true, 'AppticsRemoteConfig.fetchValue': true,
33
35
  'AppticsRemoteConfig.fetchValues': true,
34
36
  };
35
- /** How a call is named in a message: `AppticsEvents.addEvent` as it is, `flush` as `apptics.flush`. */
37
+ /** How a call is named in a message: every public call is named after its object, as `AppticsEvent.addEvent`. */
36
38
  function publicName(name) {
37
39
  return name.indexOf('Apptics') === 0 ? name : 'apptics.' + name; // no i18n
38
40
  }
@@ -68,5 +70,17 @@ function guard(name, fn) {
68
70
  };
69
71
  return guarded;
70
72
  }
73
+ /**
74
+ * Hands a public call's own `arguments` to its guarded function, exactly as they were given.
75
+ *
76
+ * guard() returns a wrapper that takes `...args`, so a browser console shows every public call as
77
+ * `(...args)`. Each public call is therefore its own function with named parameters, which is what
78
+ * the console shows, and forwards through this: `arguments` rather than the named parameters, so
79
+ * a call keeps its argument count (addEvent tells its two forms apart by it).
80
+ */
81
+ function forward(guarded, args) {
82
+ return guarded.apply(null, Array.prototype.slice.call(args));
83
+ }
71
84
 
85
+ exports.forward = forward;
72
86
  exports.guard = guard;
@@ -1,4 +1,3 @@
1
- import type { CallSite } from './callsite.js';
2
1
  import type { DeviceInfo, ServerResult } from '../types.js';
3
2
  /**
4
3
  * Late-bound calls from lower modules up to the modules above them (see spec §5). device.ts and
@@ -9,7 +8,6 @@ export declare const hooks: {
9
8
  updateDevice: (deviceInfo: DeviceInfo) => Promise<ServerResult>;
10
9
  refreshDeviceInfo: () => void;
11
10
  /** Set by remotelog/index.ts. Here, not imported, so the logger doesn't depend on the sender. */
12
- remoteLog: (module: string, message: unknown, site?: CallSite) => void;
13
11
  /**
14
12
  * Set by feedback/controls.ts: the user picked in the feedback form, or null for anonymous.
15
13
  * Here so transport can read the choice without importing the modal.
@@ -24,7 +22,7 @@ export declare const hooks: {
24
22
  */
25
23
  sendHeatmaps: (forget?: boolean) => Promise<void>;
26
24
  /** Set by heatmap/track.ts, so init() and reset() can switch capture without importing it. */
27
- enableHeatmap: (status?: boolean) => void;
25
+ trackHeatmap: (status?: boolean) => void;
28
26
  /** Set by heatmap/track.ts: clears what this visit recorded, so the cap starts again. */
29
27
  resetHeatmap: () => void;
30
28
  /** Set by remoteconfig/fetch.ts, so reset() can forget the rule set without importing it. */
@@ -36,6 +34,11 @@ export declare const hooks: {
36
34
  screenTrackedByApp: () => void;
37
35
  /** Set by remoteconfig/fetch.ts: start-up has finished, so remote config fetches its values. */
38
36
  remoteConfigStarted: () => void;
39
- /** Set by remoteconfig/fetch.ts: AppticsSetUser changed who this is, so conditions on the user re-apply. */
37
+ /** Set by remoteconfig/fetch.ts: AppticsUser.setUser changed who this is, so conditions on the user re-apply. */
40
38
  remoteConfigUserChanged: () => void;
39
+ /**
40
+ * Set by device/index.ts: getsdkconfig is asked now, outside its next_check_after. setUser calls
41
+ * it once a user is registered, and remote config when getupdates reports a module changed.
42
+ */
43
+ askServerSettings: () => void;
41
44
  };
@@ -1,4 +1,4 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  /**
@@ -9,15 +9,15 @@
9
9
  const hooks = {
10
10
  updateDevice: () => Promise.reject('apptics: device module not loaded'), // no i18n
11
11
  refreshDeviceInfo: () => { },
12
- remoteLog: () => { },
13
12
  feedbackUser: () => null,
14
13
  sendHeatmaps: () => Promise.resolve(),
15
- enableHeatmap: () => { },
14
+ trackHeatmap: () => { },
16
15
  resetHeatmap: () => { },
17
16
  resetRemoteConfig: () => { },
18
17
  screenTrackedByApp: () => { },
19
18
  remoteConfigStarted: () => { },
20
19
  remoteConfigUserChanged: () => { },
20
+ askServerSettings: () => { },
21
21
  };
22
22
 
23
23
  exports.hooks = hooks;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Runs `run` while holding the Web Lock `name`, waiting for it if another tab of this site holds
3
+ * it. Locks are shared by every tab of an origin, which is what keeps two tabs from registering
4
+ * the same browser twice or overwriting each other's session.
5
+ *
6
+ * Without the Web Locks API (older browsers), `run` simply runs, as it did before locks were used.
7
+ * Not reentrant: `run` must not ask for the same lock again, or it waits for itself.
8
+ */
9
+ export declare function withLock<T>(name: string, run: () => Promise<T>): Promise<T>;
@@ -0,0 +1,22 @@
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
+ 'use strict';
3
+
4
+ /**
5
+ * Runs `run` while holding the Web Lock `name`, waiting for it if another tab of this site holds
6
+ * it. Locks are shared by every tab of an origin, which is what keeps two tabs from registering
7
+ * the same browser twice or overwriting each other's session.
8
+ *
9
+ * Without the Web Locks API (older browsers), `run` simply runs, as it did before locks were used.
10
+ * Not reentrant: `run` must not ask for the same lock again, or it waits for itself.
11
+ */
12
+ function withLock(name, run) {
13
+ var locks = typeof navigator !== 'undefined' ? navigator.locks : undefined; // no i18n
14
+ if (!locks || typeof locks.request !== 'function') { // no i18n
15
+ return run();
16
+ }
17
+ return locks.request('apptics-' + name, function () {
18
+ return run();
19
+ });
20
+ }
21
+
22
+ exports.withLock = withLock;
@@ -8,9 +8,8 @@ export declare const Console: {
8
8
  /** Warnings the integrator must see even with debug off (e.g. missing required config). */
9
9
  export declare function warnAlways(...args: unknown[]): void;
10
10
  /**
11
- * A failure inside one of the SDK's own modules: logged to the console as usual, and sent to
12
- * console/addlog so it can be read back from the Apptics console when the SDK misbehaves in the
13
- * wild. `module` is one of AP_LOG_MODULE's values. The remote half does nothing until
14
- * the remotelog module has been loaded and its own switch allows it.
11
+ * A failure inside one of the SDK's own modules, `module` one of AP_LOG_MODULE's values: said in
12
+ * the browser console in debug mode. Nothing is sent: the Remote Logger page carries only the
13
+ * lines an app logs with AppticsLogger.
15
14
  */
16
15
  export declare function logFailure(module: string, ...args: unknown[]): void;
@@ -1,10 +1,8 @@
1
- /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
1
+ /*! @zoho_apptics/apptics-js-sdk v2.0.0-beta.2 | (c) Zoho Corporation Private Limited | see LICENSE */
2
2
  'use strict';
3
3
 
4
4
  var state = require('./state.js');
5
- var hooks = require('./hooks.js');
6
5
  var utils = require('./utils.js');
7
- var callsite = require('./callsite.js');
8
6
 
9
7
  const APConsole = typeof console !== 'undefined' ? console : null;
10
8
  function gated(method) {
@@ -38,47 +36,13 @@ function warnAlways(...args) {
38
36
  if (APConsole)
39
37
  APConsole.warn(...args);
40
38
  }
41
- function safeJson(value) {
42
- try {
43
- return JSON.stringify(value) || String(value);
44
- }
45
- catch (err) {
46
- return String(value);
47
- }
48
- }
49
39
  /**
50
- * A failure inside one of the SDK's own modules: logged to the console as usual, and sent to
51
- * console/addlog so it can be read back from the Apptics console when the SDK misbehaves in the
52
- * wild. `module` is one of AP_LOG_MODULE's values. The remote half does nothing until
53
- * the remotelog module has been loaded and its own switch allows it.
40
+ * A failure inside one of the SDK's own modules, `module` one of AP_LOG_MODULE's values: said in
41
+ * the browser console in debug mode. Nothing is sent: the Remote Logger page carries only the
42
+ * lines an app logs with AppticsLogger.
54
43
  */
55
44
  function logFailure(module, ...args) {
56
45
  Console.error.apply(null, args);
57
- hooks.hooks.remoteLog(module, args.map(function (arg) {
58
- if (arg instanceof Error) {
59
- return arg.stack || (arg.name + ': ' + arg.message); // no i18n
60
- }
61
- return typeof arg === 'string' ? arg : safeJson(arg); // no i18n
62
- }).join(' '), siteOf(args)); // no i18n
63
- }
64
- /**
65
- * Where to say the failure happened. An Error knows where it was thrown, which is the place
66
- * worth reporting; the alternative is where it was caught, which is usually a catch block three
67
- * modules away. Only a frame we could actually read counts, so an Error with no usable stack
68
- * falls through to logFailure's own caller.
69
- */
70
- function siteOf(args) {
71
- for (var i = 0; i < args.length; i++) {
72
- var arg = args[i];
73
- if (arg instanceof Error) {
74
- var thrownAt = callsite.callSiteFromStack(arg.stack, 0);
75
- if (thrownAt.linenumber > 0) {
76
- return thrownAt;
77
- }
78
- }
79
- }
80
- // past siteOf and logFailure, to whoever reported the failure
81
- return callsite.callSite(2);
82
46
  }
83
47
 
84
48
  exports.Console = Console;