@zoho_apptics/apptics-js-sdk 1.0.1 → 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.
- package/CHANGELOG.md +87 -0
- package/LICENSE +13 -0
- package/README.md +747 -11
- package/dist/apptics.esm.min.js +3 -0
- package/dist/apptics.esm.min.js.map +1 -0
- package/dist/apptics.min.js +3 -0
- package/dist/apptics.min.js.map +1 -0
- package/dist/chunks/batch-BU_mTpm1.min.js +3 -0
- package/dist/chunks/batch-BU_mTpm1.min.js.map +1 -0
- package/dist/chunks/logs-Bea5zUW_.min.js +3 -0
- package/dist/chunks/logs-Bea5zUW_.min.js.map +1 -0
- package/dist/cjs/auto-init.d.ts +8 -0
- package/dist/cjs/auto-init.js +32 -0
- package/dist/cjs/core/attempts.d.ts +28 -0
- package/dist/cjs/core/attempts.js +113 -0
- package/dist/cjs/core/batch.d.ts +32 -0
- package/dist/cjs/core/batch.js +115 -0
- package/dist/cjs/core/callsite.d.ts +28 -0
- package/dist/cjs/core/callsite.js +93 -0
- package/dist/cjs/core/consent.d.ts +23 -0
- package/dist/cjs/core/consent.js +130 -0
- package/dist/cjs/core/constants.d.ts +212 -0
- package/dist/cjs/core/constants.js +299 -0
- package/dist/cjs/core/db.d.ts +40 -0
- package/dist/cjs/core/db.js +334 -0
- package/dist/cjs/core/debug.d.ts +22 -0
- package/dist/cjs/core/debug.js +88 -0
- package/dist/cjs/core/env.d.ts +28 -0
- package/dist/cjs/core/env.js +267 -0
- package/dist/cjs/core/framework-id.d.ts +1 -0
- package/dist/cjs/core/framework-id.js +9 -0
- package/dist/cjs/core/guard.d.ts +2 -0
- package/dist/cjs/core/guard.js +72 -0
- package/dist/cjs/core/hooks.d.ts +41 -0
- package/dist/cjs/core/hooks.js +23 -0
- package/dist/cjs/core/logger.d.ts +16 -0
- package/dist/cjs/core/logger.js +86 -0
- package/dist/cjs/core/state.d.ts +69 -0
- package/dist/cjs/core/state.js +78 -0
- package/dist/cjs/core/storage.d.ts +46 -0
- package/dist/cjs/core/storage.js +229 -0
- package/dist/cjs/core/transport.d.ts +83 -0
- package/dist/cjs/core/transport.js +441 -0
- package/dist/cjs/core/utils.d.ts +26 -0
- package/dist/cjs/core/utils.js +175 -0
- package/dist/cjs/core/validate.d.ts +18 -0
- package/dist/cjs/core/validate.js +233 -0
- package/dist/cjs/device/appversion.d.ts +20 -0
- package/dist/cjs/device/appversion.js +158 -0
- package/dist/cjs/device/index.d.ts +23 -0
- package/dist/cjs/device/index.js +372 -0
- package/dist/cjs/engagement/api-rules.d.ts +84 -0
- package/dist/cjs/engagement/api-rules.js +219 -0
- package/dist/cjs/engagement/auto-api.d.ts +7 -0
- package/dist/cjs/engagement/auto-api.js +200 -0
- package/dist/cjs/engagement/auto-screen.d.ts +16 -0
- package/dist/cjs/engagement/auto-screen.js +241 -0
- package/dist/cjs/engagement/defined-events.d.ts +23 -0
- package/dist/cjs/engagement/defined-events.js +58 -0
- package/dist/cjs/engagement/send.d.ts +6 -0
- package/dist/cjs/engagement/send.js +99 -0
- package/dist/cjs/engagement/session.d.ts +42 -0
- package/dist/cjs/engagement/session.js +327 -0
- package/dist/cjs/engagement/track.d.ts +56 -0
- package/dist/cjs/engagement/track.js +350 -0
- package/dist/cjs/errors/send.d.ts +6 -0
- package/dist/cjs/errors/send.js +73 -0
- package/dist/cjs/errors/track.d.ts +4 -0
- package/dist/cjs/errors/track.js +127 -0
- package/dist/cjs/feedback/controls.d.ts +31 -0
- package/dist/cjs/feedback/controls.js +286 -0
- package/dist/cjs/feedback/index.d.ts +8 -0
- package/dist/cjs/feedback/index.js +37 -0
- package/dist/cjs/feedback/logs.d.ts +40 -0
- package/dist/cjs/feedback/logs.js +202 -0
- package/dist/cjs/feedback/send.d.ts +25 -0
- package/dist/cjs/feedback/send.js +178 -0
- package/dist/cjs/feedback/template.d.ts +2 -0
- package/dist/cjs/feedback/template.js +162 -0
- package/dist/cjs/feedback/ui.d.ts +55 -0
- package/dist/cjs/feedback/ui.js +631 -0
- package/dist/cjs/heatmap/index.d.ts +16 -0
- package/dist/cjs/heatmap/index.js +22 -0
- package/dist/cjs/heatmap/send.d.ts +13 -0
- package/dist/cjs/heatmap/send.js +82 -0
- package/dist/cjs/heatmap/track.d.ts +4 -0
- package/dist/cjs/heatmap/track.js +377 -0
- package/dist/cjs/index.d.ts +68 -0
- package/dist/cjs/index.js +150 -0
- package/dist/cjs/lifecycle.d.ts +14 -0
- package/dist/cjs/lifecycle.js +538 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/remoteconfig/custom.d.ts +10 -0
- package/dist/cjs/remoteconfig/custom.js +78 -0
- package/dist/cjs/remoteconfig/evaluate.d.ts +24 -0
- package/dist/cjs/remoteconfig/evaluate.js +171 -0
- package/dist/cjs/remoteconfig/fetch.d.ts +24 -0
- package/dist/cjs/remoteconfig/fetch.js +214 -0
- package/dist/cjs/remoteconfig/index.d.ts +13 -0
- package/dist/cjs/remoteconfig/index.js +90 -0
- package/dist/cjs/remoteconfig/store.d.ts +18 -0
- package/dist/cjs/remoteconfig/store.js +98 -0
- package/dist/cjs/remotelog/gate.d.ts +11 -0
- package/dist/cjs/remotelog/gate.js +54 -0
- package/dist/cjs/remotelog/index.d.ts +25 -0
- package/dist/cjs/remotelog/index.js +55 -0
- package/dist/cjs/remotelog/logger.d.ts +28 -0
- package/dist/cjs/remotelog/logger.js +139 -0
- package/dist/cjs/remotelog/send.d.ts +13 -0
- package/dist/cjs/remotelog/send.js +153 -0
- package/dist/cjs/scheduler.d.ts +8 -0
- package/dist/cjs/scheduler.js +78 -0
- package/dist/cjs/types.d.ts +312 -0
- package/dist/cjs/user/index.d.ts +33 -0
- package/dist/cjs/user/index.js +178 -0
- package/dist/esm/auto-init.d.ts +8 -0
- package/dist/esm/auto-init.js +29 -0
- package/dist/esm/core/attempts.d.ts +28 -0
- package/dist/esm/core/attempts.js +106 -0
- package/dist/esm/core/batch.d.ts +32 -0
- package/dist/esm/core/batch.js +108 -0
- package/dist/esm/core/callsite.d.ts +28 -0
- package/dist/esm/core/callsite.js +89 -0
- package/dist/esm/core/consent.d.ts +23 -0
- package/dist/esm/core/consent.js +120 -0
- package/dist/esm/core/constants.d.ts +212 -0
- package/dist/esm/core/constants.js +277 -0
- package/dist/esm/core/db.d.ts +40 -0
- package/dist/esm/core/db.js +324 -0
- package/dist/esm/core/debug.d.ts +22 -0
- package/dist/esm/core/debug.js +81 -0
- package/dist/esm/core/env.d.ts +28 -0
- package/dist/esm/core/env.js +251 -0
- package/dist/esm/core/framework-id.d.ts +1 -0
- package/dist/esm/core/framework-id.js +7 -0
- package/dist/esm/core/guard.d.ts +2 -0
- package/dist/esm/core/guard.js +70 -0
- package/dist/esm/core/hooks.d.ts +41 -0
- package/dist/esm/core/hooks.js +21 -0
- package/dist/esm/core/logger.d.ts +16 -0
- package/dist/esm/core/logger.js +82 -0
- package/dist/esm/core/state.d.ts +69 -0
- package/dist/esm/core/state.js +73 -0
- package/dist/esm/core/storage.d.ts +46 -0
- package/dist/esm/core/storage.js +219 -0
- package/dist/esm/core/transport.d.ts +83 -0
- package/dist/esm/core/transport.js +425 -0
- package/dist/esm/core/utils.d.ts +26 -0
- package/dist/esm/core/utils.js +161 -0
- package/dist/esm/core/validate.d.ts +18 -0
- package/dist/esm/core/validate.js +226 -0
- package/dist/esm/device/appversion.d.ts +20 -0
- package/dist/esm/device/appversion.js +153 -0
- package/dist/esm/device/index.d.ts +23 -0
- package/dist/esm/device/index.js +362 -0
- package/dist/esm/engagement/api-rules.d.ts +84 -0
- package/dist/esm/engagement/api-rules.js +211 -0
- package/dist/esm/engagement/auto-api.d.ts +7 -0
- package/dist/esm/engagement/auto-api.js +198 -0
- package/dist/esm/engagement/auto-screen.d.ts +16 -0
- package/dist/esm/engagement/auto-screen.js +238 -0
- package/dist/esm/engagement/defined-events.d.ts +23 -0
- package/dist/esm/engagement/defined-events.js +55 -0
- package/dist/esm/engagement/send.d.ts +6 -0
- package/dist/esm/engagement/send.js +96 -0
- package/dist/esm/engagement/session.d.ts +42 -0
- package/dist/esm/engagement/session.js +315 -0
- package/dist/esm/engagement/track.d.ts +56 -0
- package/dist/esm/engagement/track.js +340 -0
- package/dist/esm/errors/send.d.ts +6 -0
- package/dist/esm/errors/send.js +70 -0
- package/dist/esm/errors/track.d.ts +4 -0
- package/dist/esm/errors/track.js +123 -0
- package/dist/esm/feedback/controls.d.ts +31 -0
- package/dist/esm/feedback/controls.js +280 -0
- package/dist/esm/feedback/index.d.ts +8 -0
- package/dist/esm/feedback/index.js +30 -0
- package/dist/esm/feedback/logs.d.ts +40 -0
- package/dist/esm/feedback/logs.js +188 -0
- package/dist/esm/feedback/send.d.ts +25 -0
- package/dist/esm/feedback/send.js +175 -0
- package/dist/esm/feedback/template.d.ts +2 -0
- package/dist/esm/feedback/template.js +159 -0
- package/dist/esm/feedback/ui.d.ts +55 -0
- package/dist/esm/feedback/ui.js +626 -0
- package/dist/esm/heatmap/index.d.ts +16 -0
- package/dist/esm/heatmap/index.js +17 -0
- package/dist/esm/heatmap/send.d.ts +13 -0
- package/dist/esm/heatmap/send.js +79 -0
- package/dist/esm/heatmap/track.d.ts +4 -0
- package/dist/esm/heatmap/track.js +374 -0
- package/dist/esm/index.d.ts +68 -0
- package/dist/esm/index.js +122 -0
- package/dist/esm/lifecycle.d.ts +14 -0
- package/dist/esm/lifecycle.js +534 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/remoteconfig/custom.d.ts +10 -0
- package/dist/esm/remoteconfig/custom.js +74 -0
- package/dist/esm/remoteconfig/evaluate.d.ts +24 -0
- package/dist/esm/remoteconfig/evaluate.js +166 -0
- package/dist/esm/remoteconfig/fetch.d.ts +24 -0
- package/dist/esm/remoteconfig/fetch.js +210 -0
- package/dist/esm/remoteconfig/index.d.ts +13 -0
- package/dist/esm/remoteconfig/index.js +85 -0
- package/dist/esm/remoteconfig/store.d.ts +18 -0
- package/dist/esm/remoteconfig/store.js +91 -0
- package/dist/esm/remotelog/gate.d.ts +11 -0
- package/dist/esm/remotelog/gate.js +48 -0
- package/dist/esm/remotelog/index.d.ts +25 -0
- package/dist/esm/remotelog/index.js +51 -0
- package/dist/esm/remotelog/logger.d.ts +28 -0
- package/dist/esm/remotelog/logger.js +136 -0
- package/dist/esm/remotelog/send.d.ts +13 -0
- package/dist/esm/remotelog/send.js +149 -0
- package/dist/esm/scheduler.d.ts +8 -0
- package/dist/esm/scheduler.js +74 -0
- package/dist/esm/types.d.ts +312 -0
- package/dist/esm/user/index.d.ts +33 -0
- package/dist/esm/user/index.js +170 -0
- package/dist/feedback.esm.min.js +3 -0
- package/dist/feedback.esm.min.js.map +1 -0
- package/dist/heatmap.esm.min.js +3 -0
- package/dist/heatmap.esm.min.js.map +1 -0
- package/dist/style.css +1 -0
- package/package.json +124 -7
- package/src/appticssdk.js +0 -3817
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
|
|
2
|
+
import { Console } from './logger.js';
|
|
3
|
+
import { nowMs } from './utils.js';
|
|
4
|
+
|
|
5
|
+
const DB_NAME = 'apptics'; // no i18n
|
|
6
|
+
// 3 added the heatmaps store. The upgrade only creates stores that are missing, so an existing
|
|
7
|
+
// database keeps everything already queued in it.
|
|
8
|
+
const DB_VERSION = 3;
|
|
9
|
+
const OPEN_TIMEOUT_MS = 3000;
|
|
10
|
+
const QUEUES = ['engagements', 'errors', 'logs', 'consolelogs', 'heatmaps']; // no i18n
|
|
11
|
+
/** 1.x localStorage keys; also the layout of the localStorage backend. */
|
|
12
|
+
const LEGACY_KEYS = Object.freeze({
|
|
13
|
+
settings: 'apptics-device-info', // no i18n
|
|
14
|
+
engagements: 'apptics-engagements-transactions', // no i18n
|
|
15
|
+
errors: 'apptics-errors-transactions', // no i18n
|
|
16
|
+
logs: 'apptics-log-transactions', // no i18n
|
|
17
|
+
consolelogs: 'apptics-consolelog-transactions', // no i18n
|
|
18
|
+
// not a 1.x key: heatmaps did not exist then. It is here because this map is also the
|
|
19
|
+
// localStorage backend's layout, so the store needs a name there too
|
|
20
|
+
heatmaps: 'apptics-heatmap-transactions', // no i18n
|
|
21
|
+
});
|
|
22
|
+
/** Shape guards shared by both backends and the 1.x migration. */
|
|
23
|
+
function asList(value) {
|
|
24
|
+
return Array.isArray(value) ? value : [];
|
|
25
|
+
}
|
|
26
|
+
function asDict(value) {
|
|
27
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
28
|
+
}
|
|
29
|
+
/* ---------------- localStorage backend ---------------- */
|
|
30
|
+
function readJSON(key) {
|
|
31
|
+
try {
|
|
32
|
+
const raw = localStorage.getItem(key);
|
|
33
|
+
return raw === null || raw === '' ? null : JSON.parse(raw); // no i18n
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
Console.warn('apptics: could not read ' + key + ', treating it as empty'); // no i18n
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function writeJSON(key, value) {
|
|
41
|
+
try {
|
|
42
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
Console.warn('apptics: could not write ' + key + ': ' + String(err)); // no i18n
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function createLocalStorageBackend() {
|
|
49
|
+
return {
|
|
50
|
+
kind: 'localstorage', // no i18n
|
|
51
|
+
loadSettings() {
|
|
52
|
+
return Promise.resolve(asDict(readJSON(LEGACY_KEYS.settings)));
|
|
53
|
+
},
|
|
54
|
+
putSetting(key, value) {
|
|
55
|
+
const all = asDict(readJSON(LEGACY_KEYS.settings));
|
|
56
|
+
all[key] = value;
|
|
57
|
+
writeJSON(LEGACY_KEYS.settings, all);
|
|
58
|
+
return Promise.resolve();
|
|
59
|
+
},
|
|
60
|
+
clearSettings() {
|
|
61
|
+
writeJSON(LEGACY_KEYS.settings, {});
|
|
62
|
+
return Promise.resolve();
|
|
63
|
+
},
|
|
64
|
+
queueAll(store) {
|
|
65
|
+
return Promise.resolve(asList(readJSON(LEGACY_KEYS[store])));
|
|
66
|
+
},
|
|
67
|
+
queuePut(store, items) {
|
|
68
|
+
const list = asList(readJSON(LEGACY_KEYS[store]));
|
|
69
|
+
items.forEach(function (item) {
|
|
70
|
+
const index = list.findIndex(function (existing) { return existing.id === item.id; });
|
|
71
|
+
if (index === -1) {
|
|
72
|
+
list.push(item);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
list[index] = item;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
writeJSON(LEGACY_KEYS[store], list);
|
|
79
|
+
return Promise.resolve();
|
|
80
|
+
},
|
|
81
|
+
queueDelete(store, ids) {
|
|
82
|
+
const remaining = asList(readJSON(LEGACY_KEYS[store])).filter(function (item) {
|
|
83
|
+
return ids.indexOf(item.id) === -1;
|
|
84
|
+
});
|
|
85
|
+
writeJSON(LEGACY_KEYS[store], remaining);
|
|
86
|
+
return Promise.resolve();
|
|
87
|
+
},
|
|
88
|
+
queueClear(store) {
|
|
89
|
+
writeJSON(LEGACY_KEYS[store], []);
|
|
90
|
+
return Promise.resolve();
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
let lastSeq = 0;
|
|
95
|
+
/**
|
|
96
|
+
* Strictly increasing, and time-based so tabs interleave in roughly the right order.
|
|
97
|
+
* Counting up from the last value rather than a counter that wraps keeps insertion order
|
|
98
|
+
* even when a chatty caller adds more than a thousand items inside one millisecond.
|
|
99
|
+
*/
|
|
100
|
+
function nextSeq() {
|
|
101
|
+
const base = nowMs() * 1000;
|
|
102
|
+
lastSeq = base > lastSeq ? base : lastSeq + 1;
|
|
103
|
+
return lastSeq;
|
|
104
|
+
}
|
|
105
|
+
function request(req) {
|
|
106
|
+
return new Promise(function (resolve, reject) {
|
|
107
|
+
req.onsuccess = function () { resolve(req.result); };
|
|
108
|
+
req.onerror = function () { reject(req.error); };
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
function completed(tx) {
|
|
112
|
+
return new Promise(function (resolve, reject) {
|
|
113
|
+
tx.oncomplete = function () { resolve(); };
|
|
114
|
+
tx.onerror = function () { reject(tx.error); };
|
|
115
|
+
tx.onabort = function () { reject(tx.error); };
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
/** Puts `item` unless it exists (keepExisting) or replaces it keeping its seq. Runs inside `store`'s transaction. */
|
|
119
|
+
function putRecord(store, item, keepExisting) {
|
|
120
|
+
const id = String(item.id);
|
|
121
|
+
const lookup = store.get(id);
|
|
122
|
+
lookup.onsuccess = function () {
|
|
123
|
+
const existing = lookup.result;
|
|
124
|
+
if (existing && keepExisting) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
store.put({ id: id, seq: existing ? existing.seq : nextSeq(), type: item.type, item: item });
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Our stores, as created by onupgradeneeded. */
|
|
131
|
+
function hasAllStores(db) {
|
|
132
|
+
return db.objectStoreNames.contains('settings') && QUEUES.every(function (name) {
|
|
133
|
+
return db.objectStoreNames.contains(name);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function deleteDatabase(factory) {
|
|
137
|
+
return new Promise(function (resolve) {
|
|
138
|
+
var req = factory.deleteDatabase(DB_NAME);
|
|
139
|
+
req.onsuccess = function () { resolve(); };
|
|
140
|
+
req.onerror = function () { resolve(); };
|
|
141
|
+
req.onblocked = function () { resolve(); };
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Opens the database, and repairs it once if something else created an "apptics" database
|
|
146
|
+
* without our stores (then onupgradeneeded never fires and every read would fail).
|
|
147
|
+
*/
|
|
148
|
+
function openIndexedDB(factory = indexedDB, timeoutMs = OPEN_TIMEOUT_MS) {
|
|
149
|
+
return openOnce(factory, timeoutMs).then(function (db) {
|
|
150
|
+
if (hasAllStores(db)) {
|
|
151
|
+
return db;
|
|
152
|
+
}
|
|
153
|
+
Console.warn('apptics: the "' + DB_NAME + '" database is missing its stores, recreating it'); // no i18n
|
|
154
|
+
db.close();
|
|
155
|
+
return deleteDatabase(factory).then(function () {
|
|
156
|
+
return openOnce(factory, timeoutMs);
|
|
157
|
+
}).then(function (fresh) {
|
|
158
|
+
if (!hasAllStores(fresh)) {
|
|
159
|
+
fresh.close();
|
|
160
|
+
throw new Error('indexedDB: stores could not be created'); // no i18n
|
|
161
|
+
}
|
|
162
|
+
return fresh;
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
function openOnce(factory, timeoutMs) {
|
|
167
|
+
return new Promise(function (resolve, reject) {
|
|
168
|
+
let settled = false;
|
|
169
|
+
const fail = function (reason) {
|
|
170
|
+
if (!settled) {
|
|
171
|
+
settled = true;
|
|
172
|
+
clearTimeout(timer);
|
|
173
|
+
reject(reason);
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
const timer = setTimeout(function () {
|
|
177
|
+
fail(new Error('indexedDB open timed out')); // no i18n
|
|
178
|
+
}, timeoutMs);
|
|
179
|
+
let req;
|
|
180
|
+
try {
|
|
181
|
+
req = factory.open(DB_NAME, DB_VERSION);
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
fail(err);
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
req.onupgradeneeded = function () {
|
|
188
|
+
const db = req.result;
|
|
189
|
+
if (!db.objectStoreNames.contains('settings')) { // no i18n
|
|
190
|
+
db.createObjectStore('settings'); // no i18n
|
|
191
|
+
}
|
|
192
|
+
QUEUES.forEach(function (name) {
|
|
193
|
+
if (!db.objectStoreNames.contains(name)) {
|
|
194
|
+
db.createObjectStore(name, { keyPath: 'id' }).createIndex('seq', 'seq'); // no i18n
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
};
|
|
198
|
+
req.onsuccess = function () {
|
|
199
|
+
if (settled) {
|
|
200
|
+
req.result.close(); // we already gave up (timeout or blocked)
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
settled = true;
|
|
204
|
+
clearTimeout(timer);
|
|
205
|
+
// Another tab running a newer build needs to upgrade the schema, and cannot while this
|
|
206
|
+
// connection is open. Letting go is the only cooperative answer: holding on blocks that
|
|
207
|
+
// tab's upgrade until this one is closed, and it spends the whole time with no storage.
|
|
208
|
+
// This tab keeps working from memory and picks the new schema up on its next load.
|
|
209
|
+
req.result.onversionchange = function () {
|
|
210
|
+
Console.warn('apptics: another tab is upgrading the database, closing this connection'); // no i18n
|
|
211
|
+
req.result.close();
|
|
212
|
+
};
|
|
213
|
+
resolve(req.result);
|
|
214
|
+
};
|
|
215
|
+
req.onerror = function () {
|
|
216
|
+
fail(req.error);
|
|
217
|
+
};
|
|
218
|
+
req.onblocked = function () {
|
|
219
|
+
// Another tab is holding an older version open. A build that sets onversionchange
|
|
220
|
+
// (above) lets go by itself, so this resolves on its own in a moment; the open is left
|
|
221
|
+
// to run until the timeout rather than abandoned, because giving up here would mean
|
|
222
|
+
// running with no storage for the rest of the visit.
|
|
223
|
+
Console.warn('apptics: waiting for another tab to release the database'); // no i18n
|
|
224
|
+
};
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
function createIndexedDBBackend(db) {
|
|
228
|
+
return {
|
|
229
|
+
kind: 'indexeddb', // no i18n
|
|
230
|
+
loadSettings() {
|
|
231
|
+
const store = db.transaction('settings', 'readonly').objectStore('settings'); // no i18n
|
|
232
|
+
return Promise.all([request(store.getAllKeys()), request(store.getAll())]).then(function ([keys, values]) {
|
|
233
|
+
const out = {};
|
|
234
|
+
keys.forEach(function (key, i) {
|
|
235
|
+
out[String(key)] = values[i];
|
|
236
|
+
});
|
|
237
|
+
return out;
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
putSetting(key, value) {
|
|
241
|
+
const tx = db.transaction('settings', 'readwrite'); // no i18n
|
|
242
|
+
tx.objectStore('settings').put(value, key); // no i18n
|
|
243
|
+
return completed(tx);
|
|
244
|
+
},
|
|
245
|
+
clearSettings() {
|
|
246
|
+
const tx = db.transaction('settings', 'readwrite'); // no i18n
|
|
247
|
+
tx.objectStore('settings').clear(); // no i18n
|
|
248
|
+
return completed(tx);
|
|
249
|
+
},
|
|
250
|
+
queueAll(store) {
|
|
251
|
+
const index = db.transaction(store, 'readonly').objectStore(store).index('seq'); // no i18n
|
|
252
|
+
return request(index.getAll()).then(function (records) {
|
|
253
|
+
return records.map(function (record) { return record.item; });
|
|
254
|
+
});
|
|
255
|
+
},
|
|
256
|
+
queuePut(store, items) {
|
|
257
|
+
const tx = db.transaction(store, 'readwrite'); // no i18n
|
|
258
|
+
const objectStore = tx.objectStore(store);
|
|
259
|
+
items.forEach(function (item) { putRecord(objectStore, item, false); });
|
|
260
|
+
return completed(tx);
|
|
261
|
+
},
|
|
262
|
+
queueDelete(store, ids) {
|
|
263
|
+
const tx = db.transaction(store, 'readwrite'); // no i18n
|
|
264
|
+
const objectStore = tx.objectStore(store);
|
|
265
|
+
ids.forEach(function (id) { objectStore.delete(id); });
|
|
266
|
+
return completed(tx);
|
|
267
|
+
},
|
|
268
|
+
queueClear(store) {
|
|
269
|
+
const tx = db.transaction(store, 'readwrite'); // no i18n
|
|
270
|
+
tx.objectStore(store).clear();
|
|
271
|
+
return completed(tx);
|
|
272
|
+
},
|
|
273
|
+
importAll(settings, queues) {
|
|
274
|
+
// scope derived from QUEUES, not repeated: the loop below opens every one of them,
|
|
275
|
+
// and a store left out of the scope throws NotFoundError the moment it is reached
|
|
276
|
+
const tx = db.transaction(['settings'].concat(QUEUES), 'readwrite'); // no i18n
|
|
277
|
+
const settingsStore = tx.objectStore('settings'); // no i18n
|
|
278
|
+
Object.keys(settings).forEach(function (key) {
|
|
279
|
+
const lookup = settingsStore.get(key);
|
|
280
|
+
lookup.onsuccess = function () {
|
|
281
|
+
if (lookup.result === undefined) {
|
|
282
|
+
settingsStore.put(settings[key], key);
|
|
283
|
+
}
|
|
284
|
+
};
|
|
285
|
+
});
|
|
286
|
+
QUEUES.forEach(function (name) {
|
|
287
|
+
const objectStore = tx.objectStore(name);
|
|
288
|
+
queues[name].forEach(function (item) { putRecord(objectStore, item, true); });
|
|
289
|
+
});
|
|
290
|
+
return completed(tx);
|
|
291
|
+
},
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
function localStorageUsable() {
|
|
295
|
+
try {
|
|
296
|
+
const probe = '__apptics_probe__'; // no i18n
|
|
297
|
+
localStorage.setItem(probe, '1');
|
|
298
|
+
localStorage.removeItem(probe);
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
catch (err) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/** IndexedDB when it opens, otherwise localStorage, otherwise null. Never rejects. */
|
|
306
|
+
function openBackend() {
|
|
307
|
+
const fallback = function (reason) {
|
|
308
|
+
Console.warn('apptics: IndexedDB unavailable (' + String(reason) + '), using localStorage'); // no i18n
|
|
309
|
+
return localStorageUsable() ? createLocalStorageBackend() : null;
|
|
310
|
+
};
|
|
311
|
+
let factory;
|
|
312
|
+
try {
|
|
313
|
+
factory = typeof indexedDB !== 'undefined' ? indexedDB : undefined; // no i18n
|
|
314
|
+
}
|
|
315
|
+
catch (err) {
|
|
316
|
+
factory = undefined; // access can throw in sandboxed frames
|
|
317
|
+
}
|
|
318
|
+
if (!factory) {
|
|
319
|
+
return Promise.resolve(fallback('not supported')); // no i18n
|
|
320
|
+
}
|
|
321
|
+
return openIndexedDB(factory).then(createIndexedDBBackend, fallback);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
export { DB_NAME, DB_VERSION, LEGACY_KEYS, asDict, asList, createIndexedDBBackend, createLocalStorageBackend, openBackend, openIndexedDB };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Whether debug mode is on right now, idle hour included. */
|
|
2
|
+
export declare function debugEnabled(): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* Pushes the idle hour out. Called wherever something is actually tracked, which is the only
|
|
5
|
+
* evidence the SDK has that a person is still looking — there is no event for "watching".
|
|
6
|
+
*/
|
|
7
|
+
export declare function noteDebugActivity(): void;
|
|
8
|
+
/**
|
|
9
|
+
* Turns debug mode off if its hour has run out. Called from the flush timer, which ticks whether
|
|
10
|
+
* or not anything is happening — a check that only ran on the way into a request would never
|
|
11
|
+
* fire, because an idle SDK makes no requests.
|
|
12
|
+
*/
|
|
13
|
+
export declare function expireDebugIfIdle(): void;
|
|
14
|
+
/**
|
|
15
|
+
* Turns debug mode on, at any time: before init(), during start-up or while the SDK runs. The
|
|
16
|
+
* choice holds over `debug` in init() for the rest of the page's life.
|
|
17
|
+
*/
|
|
18
|
+
export declare function enableDebug(): void;
|
|
19
|
+
/** Turns debug mode off, at any time, with the same hold over `debug` as enableDebug(). */
|
|
20
|
+
export declare function disableDebug(): void;
|
|
21
|
+
/** What init() applies for `debug`: the config's value, unless the app has already chosen. */
|
|
22
|
+
export declare function applyDebugConfig(configured: boolean): void;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
|
|
2
|
+
import { DEBUG_IDLE_MS } from './constants.js';
|
|
3
|
+
import { _ZAP } from './state.js';
|
|
4
|
+
import { Console } from './logger.js';
|
|
5
|
+
import { nowMs } from './utils.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* The switch for debug mode, and the hour that closes it.
|
|
9
|
+
*
|
|
10
|
+
* Debug mode is not free on either side: every engagement, exception and log call goes to its
|
|
11
|
+
* `debug/` twin instead of the ordinary endpoint, which makes the server keep a traceable
|
|
12
|
+
* record of the request. That is worth it while someone is watching, and pure
|
|
13
|
+
* cost once they have walked away — and walking away is the normal way a debugging session ends,
|
|
14
|
+
* not a deliberate switch-off. So the SDK closes it: an hour with nothing tracked turns debug
|
|
15
|
+
* back off by itself, and anything tracked pushes that hour out again.
|
|
16
|
+
*
|
|
17
|
+
* It lives in core because every send asks it: `debug: true` in init(), or enableDebug(), is
|
|
18
|
+
* enough to turn the twins on, and that alone must expire.
|
|
19
|
+
*/
|
|
20
|
+
/** Whether debug mode is on right now, idle hour included. */
|
|
21
|
+
function debugEnabled() {
|
|
22
|
+
return _ZAP._config.debug_api === true && !debugIdle();
|
|
23
|
+
}
|
|
24
|
+
/** True once the idle hour has run out on a debug session nobody is watching. */
|
|
25
|
+
function debugIdle() {
|
|
26
|
+
return _ZAP._debugUntil > 0 && nowMs() > _ZAP._debugUntil;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Pushes the idle hour out. Called wherever something is actually tracked, which is the only
|
|
30
|
+
* evidence the SDK has that a person is still looking — there is no event for "watching".
|
|
31
|
+
*/
|
|
32
|
+
function noteDebugActivity() {
|
|
33
|
+
if (_ZAP._config.debug_api !== true) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
_ZAP._debugUntil = nowMs() + DEBUG_IDLE_MS;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Turns debug mode off if its hour has run out. Called from the flush timer, which ticks whether
|
|
40
|
+
* or not anything is happening — a check that only ran on the way into a request would never
|
|
41
|
+
* fire, because an idle SDK makes no requests.
|
|
42
|
+
*/
|
|
43
|
+
function expireDebugIfIdle() {
|
|
44
|
+
if (!debugIdle()) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
Console.log('apptics: debug mode has been idle for an hour, switching it off'); // no i18n
|
|
48
|
+
setDebug(false);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The app's own choice, from enableDebug() or disableDebug(). It wins over `debug` in init(),
|
|
52
|
+
* so debug mode can be switched on or off with one call, before init() runs or while the SDK is
|
|
53
|
+
* running, and an init() or reset() that comes after doesn't switch it back. null until the app
|
|
54
|
+
* has chosen.
|
|
55
|
+
*/
|
|
56
|
+
var chosen = null;
|
|
57
|
+
/** Turning it on starts the idle hour; turning it off clears it, so the next on gets a whole hour. */
|
|
58
|
+
function setDebug(on) {
|
|
59
|
+
_ZAP._config.debug_api = on;
|
|
60
|
+
_ZAP._debugUntil = on ? nowMs() + DEBUG_IDLE_MS : 0;
|
|
61
|
+
Console.log('apptics: debug mode ' + (on ? 'on' : 'off')); // no i18n
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Turns debug mode on, at any time: before init(), during start-up or while the SDK runs. The
|
|
65
|
+
* choice holds over `debug` in init() for the rest of the page's life.
|
|
66
|
+
*/
|
|
67
|
+
function enableDebug() {
|
|
68
|
+
chosen = true;
|
|
69
|
+
setDebug(true);
|
|
70
|
+
}
|
|
71
|
+
/** Turns debug mode off, at any time, with the same hold over `debug` as enableDebug(). */
|
|
72
|
+
function disableDebug() {
|
|
73
|
+
chosen = false;
|
|
74
|
+
setDebug(false);
|
|
75
|
+
}
|
|
76
|
+
/** What init() applies for `debug`: the config's value, unless the app has already chosen. */
|
|
77
|
+
function applyDebugConfig(configured) {
|
|
78
|
+
setDebug(chosen !== null ? chosen : configured);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { applyDebugConfig, debugEnabled, disableDebug, enableDebug, expireDebugIfIdle, noteDebugActivity };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AppticsConfig } from '../types.js';
|
|
2
|
+
export declare function isBlockedWS(ua: string): boolean;
|
|
3
|
+
/** Device RAM as the API wants it ("4 GB"). Chromium only; empty elsewhere. */
|
|
4
|
+
export declare function getRam(): string;
|
|
5
|
+
export declare function getConnectionType(): string;
|
|
6
|
+
export declare function getNetworkStatus(): number;
|
|
7
|
+
/**
|
|
8
|
+
* The battery as a whole percentage, or null where the browser will not say.
|
|
9
|
+
*
|
|
10
|
+
* feedbackWebSDK types `battery` as an int and the console shows it next to a report, which is
|
|
11
|
+
* what makes "it died while I was filling this in" legible. The Battery Status API is behind a
|
|
12
|
+
* promise and is absent in Firefox and Safari entirely, so this answers null rather than 0 -
|
|
13
|
+
* a real 0% and "no answer" are different things, and only one of them belongs in a report.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getBatteryPercent(): Promise<number | null>;
|
|
16
|
+
export declare function getOrientation(): number;
|
|
17
|
+
export declare function getDevice(): string;
|
|
18
|
+
export declare function getOS(): string;
|
|
19
|
+
export declare function getBrowser(): string;
|
|
20
|
+
export declare function getBrowserVersion(): number | string;
|
|
21
|
+
export declare function getReferringURL(): string;
|
|
22
|
+
export declare function getTimeZone(): string;
|
|
23
|
+
/** True for crawlers and non-browser environments; the SDK does nothing for them. */
|
|
24
|
+
export declare function is_apptics_disabled(): boolean;
|
|
25
|
+
/** Pure DNT check (no side effects). consent.hasDoNotTrackEnabled() applies NO_TRACKING. */
|
|
26
|
+
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;
|