@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,350 @@
|
|
|
1
|
+
/*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var constants = require('../core/constants.js');
|
|
5
|
+
var state = require('../core/state.js');
|
|
6
|
+
var logger = require('../core/logger.js');
|
|
7
|
+
var utils = require('../core/utils.js');
|
|
8
|
+
var storage = require('../core/storage.js');
|
|
9
|
+
var session = require('./session.js');
|
|
10
|
+
var env = require('../core/env.js');
|
|
11
|
+
var consent = require('../core/consent.js');
|
|
12
|
+
var validate = require('../core/validate.js');
|
|
13
|
+
var debug = require('../core/debug.js');
|
|
14
|
+
var hooks = require('../core/hooks.js');
|
|
15
|
+
var apiRules = require('./api-rules.js');
|
|
16
|
+
var definedEvents = require('./defined-events.js');
|
|
17
|
+
var autoScreen = require('./auto-screen.js');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Records an event: `trackEvent(name, group?, properties?)`, or a defined event with
|
|
21
|
+
* `trackEvent(DefinedEvents.AP_USER_LOGIN, properties?)`, which brings its own group.
|
|
22
|
+
*
|
|
23
|
+
* As on Android, an invalid name or group is not logged. A group left out is `default`, so the
|
|
24
|
+
* one-argument form keeps working; a group given but invalid is a mistake worth being told about,
|
|
25
|
+
* not one to file quietly under `default`.
|
|
26
|
+
*/
|
|
27
|
+
function trackEvent(eventName, groupName, jsonObj) {
|
|
28
|
+
if (!consent.canTrackEngagement('trackEvent')) { // no i18n
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
var defined = definedEvents.asDefinedEvent(eventName);
|
|
32
|
+
if (defined) {
|
|
33
|
+
// the defined event's own name and group, which alone may carry the reserved AP_ prefix
|
|
34
|
+
jsonObj = (groupName && typeof groupName === 'object' ? groupName : jsonObj); // no i18n
|
|
35
|
+
groupName = defined.group;
|
|
36
|
+
eventName = defined.event;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
if (typeof eventName !== 'string' || !validate.validateEventOrGroup(eventName)) { // no i18n
|
|
40
|
+
logger.logFailure(constants.AP_LOG_MODULE.EVENT, 'AppticsEvents.addEvent: Invalid eventName: ' + String(eventName)); // no i18n
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
if (groupName === undefined || groupName === null || groupName === '') { // no i18n
|
|
44
|
+
groupName = constants.AP_CONFIG.default_group_name;
|
|
45
|
+
}
|
|
46
|
+
else if (typeof groupName !== 'string' || !validate.validateEventOrGroup(groupName)) { // no i18n
|
|
47
|
+
logger.logFailure(constants.AP_LOG_MODULE.EVENT, 'AppticsEvents.addEvent: Invalid groupName for "' + eventName + '": ' + String(groupName)); // no i18n
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
jsonObj = jsonObj || {};
|
|
52
|
+
var _jsonObj = validate.validateJSON(jsonObj);
|
|
53
|
+
// epoch time in seconds
|
|
54
|
+
var time = utils.nowMs();
|
|
55
|
+
var eventData = {
|
|
56
|
+
id: utils.getNewUUID(),
|
|
57
|
+
type: constants.AP_CONSTANTS.EVENT,
|
|
58
|
+
group: groupName,
|
|
59
|
+
event: eventName,
|
|
60
|
+
starttime: time,
|
|
61
|
+
endtime: time,
|
|
62
|
+
edge: state._ZAP._device_info.connectionType || env.getConnectionType(),
|
|
63
|
+
networkstatus: env.getNetworkStatus(),
|
|
64
|
+
screen: state._ZAP._current_screen.screen || '', // no i18n
|
|
65
|
+
sessionstarttime: state._ZAP._current_session.starttime || time,
|
|
66
|
+
customproperties: _jsonObj
|
|
67
|
+
};
|
|
68
|
+
// save the event
|
|
69
|
+
// the session may still be waiting out its minimum; this event is what earns it
|
|
70
|
+
session.commitPendingSession();
|
|
71
|
+
debug.noteDebugActivity();
|
|
72
|
+
storage.engagement_transactions.add(eventData);
|
|
73
|
+
logger.Console.log('AppticsEvents.addEvent(\'' + eventName + '\',\'' + groupName + '\',' + JSON.stringify(_jsonObj || {}) + ')'); // no i18n
|
|
74
|
+
logger.Console.dir(eventData);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* The app's own screen view with a known id and start. The public inScreen takes the id and the
|
|
78
|
+
* time when the app calls it, so the id it hands back is the view's even when start-up is still
|
|
79
|
+
* running and this runs a moment later.
|
|
80
|
+
*/
|
|
81
|
+
function inScreenAt(screenName, jsonObj, id, startedAt) {
|
|
82
|
+
if (!validate.validateScreenName(screenName)) {
|
|
83
|
+
logger.logFailure(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreenTracker.inScreen: Invalid screenName: ' + String(screenName)); // no i18n
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
// the app named this screen itself: the automatic view of the same navigation gives way to it
|
|
87
|
+
hooks.hooks.screenTrackedByApp();
|
|
88
|
+
recordScreen(screenName, jsonObj, id, startedAt);
|
|
89
|
+
}
|
|
90
|
+
/** Ends the screen view inScreen() began, as Android's AppticsScreenTracker.outScreen(id). */
|
|
91
|
+
function outScreenAt(id, endedAt) {
|
|
92
|
+
if (utils.isEmpty(id)) {
|
|
93
|
+
logger.logFailure(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreenTracker.outScreen: no screen id given'); // no i18n
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
session.closeScreen(id, endedAt);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Queues a screen view and makes it the current screen.
|
|
100
|
+
*
|
|
101
|
+
* The view is stored open (endtime 0) and closed when the next screen starts, when the page is
|
|
102
|
+
* hidden or closed, when its session ends, or by outScreen() — which is what gives it a duration.
|
|
103
|
+
* An open view is not sent until it is closed, as an open session is not.
|
|
104
|
+
*/
|
|
105
|
+
function recordScreen(screenName, jsonObj, id, startedAt, implicit) {
|
|
106
|
+
if (!consent.canTrackEngagement('inScreen')) { // no i18n
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (!validate.validateScreenName(screenName)) {
|
|
110
|
+
logger.logFailure(constants.AP_LOG_MODULE.SCREEN, 'AppticsScreenTracker.inScreen: Invalid screenName: ' + String(screenName)); // no i18n
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
jsonObj = jsonObj || {};
|
|
114
|
+
var _jsonObj = validate.validateJSON(jsonObj);
|
|
115
|
+
// epoch time in milliseconds
|
|
116
|
+
var time = typeof startedAt === 'number' ? startedAt : utils.nowMs(); // no i18n
|
|
117
|
+
var screenData = {
|
|
118
|
+
id: id || utils.getNewUUID(),
|
|
119
|
+
type: constants.AP_CONSTANTS.SCREEN,
|
|
120
|
+
screen: screenName,
|
|
121
|
+
starttime: time,
|
|
122
|
+
endtime: 0,
|
|
123
|
+
edge: state._ZAP._device_info.connectionType || env.getConnectionType(),
|
|
124
|
+
networkstatus: env.getNetworkStatus(),
|
|
125
|
+
orientation: env.getOrientation(),
|
|
126
|
+
sessionstarttime: state._ZAP._current_session.starttime || time,
|
|
127
|
+
customproperties: _jsonObj
|
|
128
|
+
};
|
|
129
|
+
// the screen being left ends where this one starts
|
|
130
|
+
var previous = state._ZAP._current_screen && state._ZAP._current_screen.id;
|
|
131
|
+
if (previous && previous !== screenData.id) {
|
|
132
|
+
session.closeScreen(previous, time);
|
|
133
|
+
}
|
|
134
|
+
session.commitPendingSession();
|
|
135
|
+
debug.noteDebugActivity();
|
|
136
|
+
storage.engagement_transactions.add(screenData);
|
|
137
|
+
// `implicit`: a view recorded only so a heatmap record has one to belong to. Kept on the
|
|
138
|
+
// in-memory copy alone, never on the stored item, which goes to the server as it is
|
|
139
|
+
state._ZAP._current_screen = implicit ? Object.assign({}, screenData, { implicit: true }) : screenData;
|
|
140
|
+
logger.Console.log('AppticsScreenTracker.inScreen(\'' + screenName + '\',' + JSON.stringify(_jsonObj || {}) + ')'); // no i18n
|
|
141
|
+
logger.Console.dir(screenData);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The screen a heatmap record belongs to, making sure engagement/add has a view of it: the console
|
|
145
|
+
* places a record by its screen, and a screen that was never sent as a view leaves it nowhere.
|
|
146
|
+
*
|
|
147
|
+
* A screen the app or automatic screen tracking named is used as it is — that one already has its
|
|
148
|
+
* view. Otherwise (automatic tracking off and no inScreen() call) the page is named the way
|
|
149
|
+
* automatic tracking would name it, and a view is recorded for it: once per screen, a new one when
|
|
150
|
+
* the path changes, and given way as soon as anything else names the screen.
|
|
151
|
+
*/
|
|
152
|
+
function screenForRecord() {
|
|
153
|
+
var current = state._ZAP._current_screen;
|
|
154
|
+
if (current && !utils.isEmpty(current.screen) && !current.implicit) {
|
|
155
|
+
return String(current.screen);
|
|
156
|
+
}
|
|
157
|
+
var name = autoScreen.automaticScreenName() || '/'; // no i18n
|
|
158
|
+
if (!current || !current.id || current.screen !== name || current.endtime) {
|
|
159
|
+
recordScreen(name, undefined, undefined, undefined, true);
|
|
160
|
+
}
|
|
161
|
+
return name;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Back in view after being hidden: the hide ended the screen view, so the screen the user is on
|
|
165
|
+
* starts a new one, as an Android activity coming back to the foreground does.
|
|
166
|
+
*/
|
|
167
|
+
function resumeScreen() {
|
|
168
|
+
var current = state._ZAP._current_screen;
|
|
169
|
+
if (!current || !current.id || !current.endtime || utils.isEmpty(current.screen)) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
recordScreen(String(current.screen));
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* What the proxy accepts as an api item's hostname and path (security-regex.xml: api_hostname,
|
|
176
|
+
* api_urlpath). It validates these before the server sees them, and a rejected item is dropped
|
|
177
|
+
* there — nothing reaches the console and nothing says why. Checking here means trackApi can
|
|
178
|
+
* repair or refuse the value while there is still a caller to tell.
|
|
179
|
+
*/
|
|
180
|
+
const API_HOSTNAME = /^([a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/;
|
|
181
|
+
const API_PATH_DISALLOWED = /[^a-zA-Z0-9\-._*\/]+/g;
|
|
182
|
+
/**
|
|
183
|
+
* Rewrites a path to the characters the proxy allows, one `*` per run of anything else, so an id
|
|
184
|
+
* that happens to hold an email or an encoded character costs that segment's detail rather than
|
|
185
|
+
* the whole call. Segment boundaries survive, which is what the console groups by.
|
|
186
|
+
*/
|
|
187
|
+
function sanitizeApiPath(path) {
|
|
188
|
+
if (utils.isEmpty(path)) {
|
|
189
|
+
return '/'; // no i18n
|
|
190
|
+
}
|
|
191
|
+
var cleaned = path.replace(API_PATH_DISALLOWED, '*'); // no i18n
|
|
192
|
+
return cleaned.charAt(0) === '/' ? cleaned : '/' + cleaned; // no i18n
|
|
193
|
+
}
|
|
194
|
+
/** A path for a log line, without the query, which can carry tokens. */
|
|
195
|
+
function withoutQueryForLog(path) {
|
|
196
|
+
return String(path || '').split(/[?#]/)[0]; // no i18n
|
|
197
|
+
}
|
|
198
|
+
function trackApi(jsonObj) {
|
|
199
|
+
if (!consent.canTrackEngagement('trackApi')) { // no i18n
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
jsonObj = jsonObj || {};
|
|
203
|
+
// Extract raw values from jsonObj (from XHR/fetch hook or manual calls)
|
|
204
|
+
var rawUrl = jsonObj.url || jsonObj.path || '';
|
|
205
|
+
var method = (jsonObj.method || 'GET').toString();
|
|
206
|
+
var responsecode = (typeof jsonObj.responsecode === 'number') ? jsonObj.responsecode :
|
|
207
|
+
(typeof jsonObj.status === 'number') ? jsonObj.status : 0;
|
|
208
|
+
// the template requires this key, and fetch leaves statusText empty on HTTP/2, so a
|
|
209
|
+
// placeholder stands in rather than risking the item being refused for an empty value
|
|
210
|
+
var responsemessage = jsonObj.responsemessage || jsonObj.statusText || jsonObj.error || '-';
|
|
211
|
+
// Time fields (ms since epoch, consistent with other trackers)
|
|
212
|
+
var now = utils.nowMs();
|
|
213
|
+
var starttime = (typeof jsonObj.starttime === 'number') ? jsonObj.starttime : now;
|
|
214
|
+
var endtime;
|
|
215
|
+
if (typeof jsonObj.endtime === 'number') {
|
|
216
|
+
endtime = jsonObj.endtime;
|
|
217
|
+
}
|
|
218
|
+
else if (typeof jsonObj.duration === 'number') {
|
|
219
|
+
endtime = starttime + jsonObj.duration;
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
endtime = now;
|
|
223
|
+
}
|
|
224
|
+
// URL breakdown: scheme, hostname, port, path
|
|
225
|
+
var scheme = jsonObj.scheme || '';
|
|
226
|
+
var hostname = jsonObj.hostname || '';
|
|
227
|
+
var port = (typeof jsonObj.port === 'number') ? jsonObj.port : 0;
|
|
228
|
+
var path = jsonObj.path || '';
|
|
229
|
+
if (!utils.isEmpty(rawUrl)) {
|
|
230
|
+
try {
|
|
231
|
+
var urlObj = new URL(rawUrl, window.location.origin);
|
|
232
|
+
if (utils.isEmpty(scheme)) {
|
|
233
|
+
scheme = urlObj.protocol.replace(':', ''); // "https:"
|
|
234
|
+
}
|
|
235
|
+
if (utils.isEmpty(hostname)) {
|
|
236
|
+
hostname = urlObj.hostname;
|
|
237
|
+
}
|
|
238
|
+
if (!port) {
|
|
239
|
+
if (urlObj.port) {
|
|
240
|
+
port = parseInt(urlObj.port, 10);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
port = (urlObj.protocol === 'https:') ? 443 : 80;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
if (utils.isEmpty(path)) {
|
|
247
|
+
path = urlObj.pathname;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (e) {
|
|
251
|
+
// Fallback: treat rawUrl as path if parsing fails
|
|
252
|
+
if (utils.isEmpty(path)) {
|
|
253
|
+
path = rawUrl;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// only http and https exist as far as the proxy's api_scheme is concerned
|
|
258
|
+
scheme = (scheme === 'https' || scheme === 'http') ? scheme : 'https'; // no i18n
|
|
259
|
+
// a hostname the proxy refuses cannot be repaired without inventing one, so the call is
|
|
260
|
+
// dropped here and said out loud. localhost and bare IPs land here: api_hostname wants at
|
|
261
|
+
// least one dot and an alphabetic suffix, which is worth knowing when nothing shows up locally
|
|
262
|
+
if (!API_HOSTNAME.test(hostname)) {
|
|
263
|
+
logger.logFailure(constants.AP_LOG_MODULE.API, 'AppticsApiTracker: hostname not accepted by the server: ' + String(hostname)); // no i18n
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// configureApiTracking: the app's rules decide whether this call is recorded at all
|
|
267
|
+
if (!apiRules.hostAllowed(hostname) || apiRules.endpointIgnored(path)) {
|
|
268
|
+
logger.Console.log('AppticsApiTracker: ' + hostname + withoutQueryForLog(path) + ' is left out by configureApiTracking'); // no i18n
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
// and the name it is recorded under: ids become *, regional hosts one group, so the console
|
|
272
|
+
// groups calls by endpoint rather than by every id that went through it
|
|
273
|
+
path = sanitizeApiPath(apiRules.normalizeApiPath(path));
|
|
274
|
+
hostname = apiRules.groupedHost(hostname);
|
|
275
|
+
var sessionStart = state._ZAP._current_session.starttime || starttime;
|
|
276
|
+
// no customproperties: apiWebSDK does not declare the key, unlike the screen and event
|
|
277
|
+
// templates, so anything extra the caller passes is context for the log line only
|
|
278
|
+
var apiData = {
|
|
279
|
+
id: utils.getNewUUID(),
|
|
280
|
+
type: constants.AP_CONSTANTS.API,
|
|
281
|
+
// Required by backend schema
|
|
282
|
+
scheme: scheme,
|
|
283
|
+
port: port,
|
|
284
|
+
hostname: hostname,
|
|
285
|
+
path: path,
|
|
286
|
+
method: method,
|
|
287
|
+
responsecode: responsecode,
|
|
288
|
+
responsemessage: responsemessage,
|
|
289
|
+
starttime: starttime,
|
|
290
|
+
endtime: endtime,
|
|
291
|
+
sessionstarttime: sessionStart,
|
|
292
|
+
networkstatus: env.getNetworkStatus(),
|
|
293
|
+
edge: state._ZAP._device_info.connectionType || env.getConnectionType()
|
|
294
|
+
};
|
|
295
|
+
// save the api
|
|
296
|
+
session.commitPendingSession();
|
|
297
|
+
debug.noteDebugActivity();
|
|
298
|
+
storage.engagement_transactions.add(apiData);
|
|
299
|
+
logger.Console.log('AppticsApiTracker(\'' + method + ' ' + scheme + '://' + hostname + path + '\')'); // no i18n
|
|
300
|
+
logger.Console.dir(apiData);
|
|
301
|
+
}
|
|
302
|
+
/** Begun calls by id. Bounded, so an app that starts calls it never ends can't grow it forever. */
|
|
303
|
+
var openCalls = {};
|
|
304
|
+
var openOrder = [];
|
|
305
|
+
const MAX_OPEN_CALLS = 500;
|
|
306
|
+
/**
|
|
307
|
+
* Begins timing one API call, as Android's AppticsApiTracker.startTrackApi(url, method): returns
|
|
308
|
+
* the id to hand to endTrackApi once the response is in. Records nothing by itself.
|
|
309
|
+
*/
|
|
310
|
+
function startTrackApi(url, method) {
|
|
311
|
+
var id = utils.getNewUUID();
|
|
312
|
+
openCalls[id] = { url: String(url || ''), method: String(method || 'GET').toUpperCase(), starttime: utils.nowMs() }; // no i18n
|
|
313
|
+
openOrder.push(id);
|
|
314
|
+
if (openOrder.length > MAX_OPEN_CALLS) {
|
|
315
|
+
delete openCalls[openOrder.shift()];
|
|
316
|
+
}
|
|
317
|
+
return id;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Finishes a call startTrackApi began and records it, timed from start to `endedAt`. The public
|
|
321
|
+
* wrapper takes `endedAt` when the app calls it, so a call ended while start-up is still running
|
|
322
|
+
* keeps its real duration even though it is recorded a moment later.
|
|
323
|
+
*/
|
|
324
|
+
function endTrackApiAt(id, responseCode, responseMessage, endedAt) {
|
|
325
|
+
var open = openCalls[id];
|
|
326
|
+
if (!open) {
|
|
327
|
+
logger.logFailure(constants.AP_LOG_MODULE.API, 'AppticsApiTracker.endTrackApi: no call started with id ' + String(id)); // no i18n
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
delete openCalls[id];
|
|
331
|
+
openOrder = openOrder.filter(function (one) { return one !== id; });
|
|
332
|
+
trackApi({
|
|
333
|
+
url: open.url,
|
|
334
|
+
method: open.method,
|
|
335
|
+
responsecode: typeof responseCode === 'number' ? responseCode : 0, // no i18n
|
|
336
|
+
responsemessage: responseMessage,
|
|
337
|
+
starttime: open.starttime,
|
|
338
|
+
endtime: endedAt,
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
exports.endTrackApiAt = endTrackApiAt;
|
|
343
|
+
exports.inScreenAt = inScreenAt;
|
|
344
|
+
exports.outScreenAt = outScreenAt;
|
|
345
|
+
exports.recordScreen = recordScreen;
|
|
346
|
+
exports.resumeScreen = resumeScreen;
|
|
347
|
+
exports.screenForRecord = screenForRecord;
|
|
348
|
+
exports.startTrackApi = startTrackApi;
|
|
349
|
+
exports.trackApi = trackApi;
|
|
350
|
+
exports.trackEvent = trackEvent;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Dict, ServerResult } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sends pending errors to the Apptics API.
|
|
4
|
+
*/
|
|
5
|
+
export declare function sendErrorData(forget?: boolean): Promise<void>;
|
|
6
|
+
export declare function requestToSendErrors(_payload: Dict, forget?: boolean): Promise<ServerResult>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var state = require('../core/state.js');
|
|
5
|
+
var logger = require('../core/logger.js');
|
|
6
|
+
var utils = require('../core/utils.js');
|
|
7
|
+
var storage = require('../core/storage.js');
|
|
8
|
+
var env = require('../core/env.js');
|
|
9
|
+
var consent = require('../core/consent.js');
|
|
10
|
+
var batch = require('../core/batch.js');
|
|
11
|
+
var transport = require('../core/transport.js');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Sends pending errors to the Apptics API.
|
|
15
|
+
*/
|
|
16
|
+
function sendErrorData(forget) {
|
|
17
|
+
// errortracking off (getupdates): queued errors stay until tracking is back on or they expire
|
|
18
|
+
if (env.is_apptics_disabled() || !consent.shouldTrackOrSendData() || !state._ZAP._errorTracking) {
|
|
19
|
+
return Promise.resolve();
|
|
20
|
+
}
|
|
21
|
+
if (navigator.onLine == false) {
|
|
22
|
+
logger.Console.warn('sendErrorData: No Network'); // no i18n
|
|
23
|
+
return Promise.resolve();
|
|
24
|
+
}
|
|
25
|
+
// if we're busy sending, retry in .5s
|
|
26
|
+
if (state._ZAP._sending) {
|
|
27
|
+
batch.defer(sendErrorData);
|
|
28
|
+
return Promise.resolve();
|
|
29
|
+
}
|
|
30
|
+
state._ZAP._sending = true;
|
|
31
|
+
batch.clearDefer();
|
|
32
|
+
return batch.withSendLock('errors', function () {
|
|
33
|
+
return batch.freshItems(storage.error_transactions, function (item) { return item.happenedat != 0; }, function (item) { return item.happenedat; }).then(function (error_items) {
|
|
34
|
+
if (error_items.length == 0) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
let exceptiondetails = [];
|
|
38
|
+
var sent = [];
|
|
39
|
+
utils.cloneObject(error_items).forEach(function (item) {
|
|
40
|
+
sent.push({ ...item });
|
|
41
|
+
if (!item.hasOwnProperty('screenname')) { // no i18n
|
|
42
|
+
item.screenname = ''; // no i18n
|
|
43
|
+
}
|
|
44
|
+
delete item.id;
|
|
45
|
+
delete item.type;
|
|
46
|
+
exceptiondetails.push(item);
|
|
47
|
+
});
|
|
48
|
+
return batch.awaitUnlessClosing(requestToSendErrors({ exceptiondetails: exceptiondetails }, forget).then(function () {
|
|
49
|
+
return storage.error_transactions.remove(sent);
|
|
50
|
+
}, function (err) {
|
|
51
|
+
// the server will never accept this batch. Keeping it would block every later
|
|
52
|
+
// batch behind it for good, so it is dropped and said out loud
|
|
53
|
+
if (transport.isPermanentRefusal(err)) {
|
|
54
|
+
logger.warnAlways('apptics: the server refused these errors, so they were dropped: ' + String(err && err.message)); // no i18n
|
|
55
|
+
return storage.error_transactions.remove(sent);
|
|
56
|
+
}
|
|
57
|
+
return Promise.reject(err);
|
|
58
|
+
}), forget, 'sendErrorData'); // no i18n
|
|
59
|
+
});
|
|
60
|
+
}).catch(function (err) {
|
|
61
|
+
logger.Console.log('sendErrorData:' + err); // no i18n
|
|
62
|
+
}).then(function () {
|
|
63
|
+
state._ZAP._sending = false;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Function to send error data to server
|
|
67
|
+
function requestToSendErrors(_payload, forget) {
|
|
68
|
+
var label = 'requestToSendErrors'; // no i18n
|
|
69
|
+
return batch.sendBatch('error', label, _payload, forget); // no i18n
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
exports.requestToSendErrors = requestToSendErrors;
|
|
73
|
+
exports.sendErrorData = sendErrorData;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Properties } from '../types.js';
|
|
2
|
+
export declare function trackError(errorEvent: any, jsonObj?: Properties): void;
|
|
3
|
+
export declare function enableGlobalErrorHandler(status?: boolean): void;
|
|
4
|
+
export declare function extractMethodNameFromStackTrace(stackTrace: string): string;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/*! @zoho_apptics/apptics-js-sdk v2.0.0-beta | (c) Zoho Corporation Private Limited | see LICENSE */
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
var constants = require('../core/constants.js');
|
|
5
|
+
var state = require('../core/state.js');
|
|
6
|
+
var logger = require('../core/logger.js');
|
|
7
|
+
var utils = require('../core/utils.js');
|
|
8
|
+
var storage = require('../core/storage.js');
|
|
9
|
+
var session = require('../engagement/session.js');
|
|
10
|
+
var env = require('../core/env.js');
|
|
11
|
+
var consent = require('../core/consent.js');
|
|
12
|
+
var validate = require('../core/validate.js');
|
|
13
|
+
var debug = require('../core/debug.js');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The stack to report. Three sources, in order of how much they tell us:
|
|
17
|
+
*
|
|
18
|
+
* `reason.stack` and `error.stack` are where a promise rejection and a window error event keep it.
|
|
19
|
+
* `errorEvent.stack` covers an Error handed straight to trackError — `trackError(new Error('x'))`
|
|
20
|
+
* is the first thing anyone writes, and reading only the wrapped forms lost its trace silently.
|
|
21
|
+
*
|
|
22
|
+
* Failing all of those, a cross-origin script error or a non-Error throw carries no stack at all,
|
|
23
|
+
* and the event's own filename, line and column are the only detail there is, so they are written
|
|
24
|
+
* as a one-frame stack rather than discarded.
|
|
25
|
+
*/
|
|
26
|
+
function stackOf(errorEvent) {
|
|
27
|
+
var stack = errorEvent.reason?.stack || errorEvent.error?.stack || errorEvent.stack || ''; // no i18n
|
|
28
|
+
if (!utils.isEmpty(stack)) {
|
|
29
|
+
return stack;
|
|
30
|
+
}
|
|
31
|
+
var file = errorEvent.filename || errorEvent.fileName || ''; // no i18n
|
|
32
|
+
if (utils.isEmpty(file)) {
|
|
33
|
+
return ''; // no i18n
|
|
34
|
+
}
|
|
35
|
+
var line = errorEvent.lineno !== undefined ? errorEvent.lineno : errorEvent.lineNumber;
|
|
36
|
+
var column = errorEvent.colno !== undefined ? errorEvent.colno : errorEvent.columnNumber;
|
|
37
|
+
return 'at ' + file + (utils.isEmpty(line) ? '' : ':' + line) + (utils.isEmpty(column) ? '' : ':' + column); // no i18n
|
|
38
|
+
}
|
|
39
|
+
/** Said in place of a stack when there is none, so `message` is never sent empty. */
|
|
40
|
+
const NO_STACK = 'no stack available'; // no i18n
|
|
41
|
+
function trackError(errorEvent, jsonObj) {
|
|
42
|
+
if (!consent.canTrackErrors('trackError')) { // no i18n
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
if (utils.isEmpty(errorEvent)) {
|
|
46
|
+
logger.Console.warn('AppticsTrackError: Invalid error'); // no i18n
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
var _jsonObj = validate.validateJSON(jsonObj);
|
|
50
|
+
var stack = stackOf(errorEvent);
|
|
51
|
+
var methodName = extractMethodNameFromStackTrace(stack) || "";
|
|
52
|
+
var issuetype = errorEvent.type || "";
|
|
53
|
+
var thrown = errorEvent.reason || errorEvent.error || errorEvent.message || "";
|
|
54
|
+
// "Error: x at handler", or just "Error: x" when the stack names no method. issuename is
|
|
55
|
+
// required too, so something that carried no message at all is still named rather than blank
|
|
56
|
+
var described = !utils.isEmpty(String(thrown)) ? String(thrown) : (!utils.isEmpty(issuetype) ? String(issuetype) : 'Unknown error'); // no i18n
|
|
57
|
+
var message = described + (utils.isEmpty(methodName) ? "" : ' at ' + methodName);
|
|
58
|
+
// epoch time in seconds
|
|
59
|
+
var time = utils.nowMs();
|
|
60
|
+
var errorData = {
|
|
61
|
+
id: utils.getNewUUID(),
|
|
62
|
+
type: constants.AP_CONSTANTS.ERROR,
|
|
63
|
+
edge: state._ZAP._device_info.connectionType || env.getConnectionType(),
|
|
64
|
+
networkstatus: env.getNetworkStatus(),
|
|
65
|
+
happenedat: time,
|
|
66
|
+
issuename: message,
|
|
67
|
+
// the template requires this key, so a stackless error still says something: an empty value
|
|
68
|
+
// risks the proxy refusing the item, and errors travel in batches
|
|
69
|
+
message: !utils.isEmpty(stack) ? stack : (!utils.isEmpty(String(thrown)) ? String(thrown) : NO_STACK),
|
|
70
|
+
screenname: state._ZAP._current_screen.screen || window.location.pathname,
|
|
71
|
+
sessionstarttime: state._ZAP._current_session.starttime || time,
|
|
72
|
+
customproperties: _jsonObj
|
|
73
|
+
};
|
|
74
|
+
// save the error
|
|
75
|
+
// an error is worth a session even in the first seconds of a visit
|
|
76
|
+
session.commitPendingSession();
|
|
77
|
+
debug.noteDebugActivity();
|
|
78
|
+
storage.error_transactions.add(errorData);
|
|
79
|
+
logger.Console.log('AppticsTrackError(\'' + issuetype + '\',\'' + message + '\',' + JSON.stringify(_jsonObj || {}) + ')'); // no i18n
|
|
80
|
+
logger.Console.dir(errorData);
|
|
81
|
+
}
|
|
82
|
+
function enableGlobalErrorHandler(status) {
|
|
83
|
+
state._ZAP._isGlobalErrorTracking = typeof status === "boolean" ? status : true; // no i18n
|
|
84
|
+
}
|
|
85
|
+
function extractMethodNameFromStackTrace(stackTrace) {
|
|
86
|
+
let methodName = ''; // no i18n
|
|
87
|
+
if (utils.isEmpty(stackTrace)) {
|
|
88
|
+
return methodName;
|
|
89
|
+
}
|
|
90
|
+
const lines = stackTrace.split('\n'); // no i18n
|
|
91
|
+
if (lines.length < 2) {
|
|
92
|
+
return methodName; // Not enough information in the stack trace
|
|
93
|
+
}
|
|
94
|
+
// The method name is typically included in the second line
|
|
95
|
+
const methodNamePattern1 = /at (\S+) \(/;
|
|
96
|
+
const methodNamePattern2 = /^(\w+)@/;
|
|
97
|
+
for (let line of lines) {
|
|
98
|
+
const match1 = line.match(methodNamePattern1);
|
|
99
|
+
const match2 = line.match(methodNamePattern2);
|
|
100
|
+
// For browsers like Chrome, Ula
|
|
101
|
+
if (match1 && match1[1]) {
|
|
102
|
+
// Return the method name
|
|
103
|
+
const urlRegex = /\((.*)\)/;
|
|
104
|
+
// Extract the URL from the error string
|
|
105
|
+
const urlMatch = urlRegex.exec(line);
|
|
106
|
+
// Extracted URL
|
|
107
|
+
const url = urlMatch ? urlMatch[1] : 'Unknown URL'; // no i18n
|
|
108
|
+
methodName = match1[1];
|
|
109
|
+
url.split('/').pop(); // no i18n
|
|
110
|
+
methodName = methodName; // + '@'+ fileNameAndLine;
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
// For browsers like Safari
|
|
114
|
+
if (match2 && match2[1]) {
|
|
115
|
+
// Return the method name
|
|
116
|
+
methodName = match2[1];
|
|
117
|
+
line.split('@')[1].split('/').pop(); // no i18n
|
|
118
|
+
methodName = methodName; // + '@'+ fileNameAndLine; // no i18n
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return methodName;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
exports.enableGlobalErrorHandler = enableGlobalErrorHandler;
|
|
126
|
+
exports.extractMethodNameFromStackTrace = extractMethodNameFromStackTrace;
|
|
127
|
+
exports.trackError = trackError;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Dict } from '../types.js';
|
|
2
|
+
/** Who the next submission is attributed to: the picked user, or nobody. */
|
|
3
|
+
export interface UserChoice {
|
|
4
|
+
anonymous: boolean;
|
|
5
|
+
userid: string;
|
|
6
|
+
groupid: string;
|
|
7
|
+
}
|
|
8
|
+
/** Read by core/transport when it builds the feedback request's parameters. */
|
|
9
|
+
export declare const userChoice: UserChoice;
|
|
10
|
+
/** Whether the next submission carries the stored logs and diagnostics. Unset means "decide from what is stored". */
|
|
11
|
+
export declare const logChoice: {
|
|
12
|
+
includeLog?: boolean;
|
|
13
|
+
includeDyninfo?: boolean;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* The "User" dropdown above the description. It lists Anonymous plus every registered user, and
|
|
17
|
+
* starts on the active one (status 1) unless the caller asked for anonymous.
|
|
18
|
+
*/
|
|
19
|
+
export declare function wireUserPicker(modal: HTMLElement, forceAnonymous: boolean): void;
|
|
20
|
+
/**
|
|
21
|
+
* The two "Include …" switches and the viewer behind their View links. A row is shown only when
|
|
22
|
+
* there is something to include, and is then on by default, so a submission carries what the app
|
|
23
|
+
* recorded unless the user turns it off.
|
|
24
|
+
*/
|
|
25
|
+
export declare function wireLogControls(modal: HTMLElement, opts: Dict): void;
|
|
26
|
+
/**
|
|
27
|
+
* Drags the dialog by its header. The right/bottom placement from the stylesheet is converted to
|
|
28
|
+
* an explicit left/top on the first drag, so the offsets have something to add to, and the box is
|
|
29
|
+
* kept inside the viewport.
|
|
30
|
+
*/
|
|
31
|
+
export declare function wireDrag(box: HTMLElement): void;
|