@atlaskit/insm 0.0.2 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/README.md +203 -5
- package/dist/cjs/index.js +55 -1
- package/dist/cjs/inp-measurers/inp.js +184 -0
- package/dist/cjs/insm-period.js +345 -0
- package/dist/cjs/insm-session.js +183 -0
- package/dist/cjs/insm.js +129 -0
- package/dist/cjs/period-measurers/afps.js +193 -0
- package/dist/cjs/types.js +5 -0
- package/dist/es2019/index.js +54 -1
- package/dist/es2019/inp-measurers/inp.js +142 -0
- package/dist/es2019/insm-period.js +246 -0
- package/dist/es2019/insm-session.js +149 -0
- package/dist/es2019/insm.js +105 -0
- package/dist/es2019/period-measurers/afps.js +153 -0
- package/dist/es2019/types.js +1 -0
- package/dist/esm/index.js +54 -1
- package/dist/esm/inp-measurers/inp.js +177 -0
- package/dist/esm/insm-period.js +339 -0
- package/dist/esm/insm-session.js +177 -0
- package/dist/esm/insm.js +122 -0
- package/dist/esm/period-measurers/afps.js +186 -0
- package/dist/esm/types.js +1 -0
- package/dist/types/index.d.ts +10 -1
- package/dist/types/inp-measurers/inp.d.ts +37 -0
- package/dist/types/insm-period.d.ts +72 -0
- package/dist/types/insm-session.d.ts +91 -0
- package/dist/types/insm.d.ts +61 -0
- package/dist/types/period-measurers/afps.d.ts +57 -0
- package/dist/types/types.d.ts +81 -0
- package/dist/types-ts4.5/index.d.ts +10 -1
- package/dist/types-ts4.5/inp-measurers/inp.d.ts +37 -0
- package/dist/types-ts4.5/insm-period.d.ts +72 -0
- package/dist/types-ts4.5/insm-session.d.ts +91 -0
- package/dist/types-ts4.5/insm.d.ts +61 -0
- package/dist/types-ts4.5/period-measurers/afps.d.ts +57 -0
- package/dist/types-ts4.5/types.d.ts +81 -0
- package/package.json +6 -5
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.PeriodTracking = void 0;
|
|
8
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
12
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
13
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
14
|
+
/* eslint-disable @repo/internal/dom-events/no-unsafe-event-listeners */
|
|
15
|
+
var PeriodTracking = exports.PeriodTracking = /*#__PURE__*/function () {
|
|
16
|
+
function PeriodTracking(session) {
|
|
17
|
+
(0, _classCallCheck2.default)(this, PeriodTracking);
|
|
18
|
+
(0, _defineProperty2.default)(this, "periodMeasurements", {
|
|
19
|
+
active: {
|
|
20
|
+
features: new Set(),
|
|
21
|
+
heavyTasks: new Set(),
|
|
22
|
+
measurements: {},
|
|
23
|
+
duration: 0,
|
|
24
|
+
count: 0
|
|
25
|
+
},
|
|
26
|
+
inactive: {
|
|
27
|
+
features: new Set(),
|
|
28
|
+
heavyTasks: new Set(),
|
|
29
|
+
measurements: {},
|
|
30
|
+
duration: 0,
|
|
31
|
+
count: 0
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
(0, _defineProperty2.default)(this, "state", 'inactive');
|
|
35
|
+
(0, _defineProperty2.default)(this, "pauses", new Set());
|
|
36
|
+
/**
|
|
37
|
+
* Warning: this can be reset mid period when pausing/resuming.
|
|
38
|
+
* It's intended use is to build the `periodMeasurements` duration.
|
|
39
|
+
*/
|
|
40
|
+
(0, _defineProperty2.default)(this, "currentPeriodStart", performance.now());
|
|
41
|
+
(0, _defineProperty2.default)(this, "activeStartListeners", []);
|
|
42
|
+
(0, _defineProperty2.default)(this, "activeEndListeners", []);
|
|
43
|
+
/**
|
|
44
|
+
* This works by;
|
|
45
|
+
* On setup
|
|
46
|
+
* - starts activity listeners
|
|
47
|
+
* - on activity received
|
|
48
|
+
* - possible end active count down started.
|
|
49
|
+
* 3 animation frames or 3 seconds of inactivity - whichever comes first
|
|
50
|
+
* - any existing end count down ended
|
|
51
|
+
*/
|
|
52
|
+
(0, _defineProperty2.default)(this, "activeEndCountDownAbortController", new AbortController());
|
|
53
|
+
this.session = session;
|
|
54
|
+
this.latestPeriodFeatures = new Set(session.runningFeatures);
|
|
55
|
+
this.latestHeavyTasks = new Set(session.insm.runningHeavyTasks);
|
|
56
|
+
this.pauses = new Set(session.insm.runningHeavyTasks);
|
|
57
|
+
var startInteractivityMeasuresPaused = this.latestHeavyTasks.size !== 0;
|
|
58
|
+
var _iterator = _createForOfIteratorHelper(session.insm.periodMeasurers),
|
|
59
|
+
_step;
|
|
60
|
+
try {
|
|
61
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
62
|
+
var periodMeasurer = _step.value;
|
|
63
|
+
periodMeasurer.start(startInteractivityMeasuresPaused);
|
|
64
|
+
this.periodMeasurements.active.measurements[periodMeasurer.name] = {
|
|
65
|
+
numerator: 0,
|
|
66
|
+
denominator: 0,
|
|
67
|
+
max: 0,
|
|
68
|
+
min: 0,
|
|
69
|
+
average: 0
|
|
70
|
+
};
|
|
71
|
+
this.periodMeasurements.inactive.measurements[periodMeasurer.name] = {
|
|
72
|
+
numerator: 0,
|
|
73
|
+
denominator: 0,
|
|
74
|
+
max: 0,
|
|
75
|
+
min: 0,
|
|
76
|
+
average: 0
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
} catch (err) {
|
|
80
|
+
_iterator.e(err);
|
|
81
|
+
} finally {
|
|
82
|
+
_iterator.f();
|
|
83
|
+
}
|
|
84
|
+
this.setupActiveStartInteractionListeners();
|
|
85
|
+
}
|
|
86
|
+
return (0, _createClass2.default)(PeriodTracking, [{
|
|
87
|
+
key: "startFeature",
|
|
88
|
+
value: function startFeature(featureName) {
|
|
89
|
+
this.latestPeriodFeatures.add(featureName);
|
|
90
|
+
this.periodMeasurements[this.state].features.add(featureName);
|
|
91
|
+
}
|
|
92
|
+
}, {
|
|
93
|
+
key: "startHeavyTask",
|
|
94
|
+
value: function startHeavyTask(heavyTaskName) {
|
|
95
|
+
this.latestHeavyTasks.add(heavyTaskName);
|
|
96
|
+
this.periodMeasurements[this.state].heavyTasks.add(heavyTaskName);
|
|
97
|
+
this.pause(heavyTaskName);
|
|
98
|
+
}
|
|
99
|
+
}, {
|
|
100
|
+
key: "endHeavyTask",
|
|
101
|
+
value: function endHeavyTask(heavyTaskName) {
|
|
102
|
+
this.resume(heavyTaskName);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Sets a pause based on a key. If this is the first pause, then it will also halt
|
|
107
|
+
* running interactivity measures, and update the current measurements duration.
|
|
108
|
+
*/
|
|
109
|
+
}, {
|
|
110
|
+
key: "pause",
|
|
111
|
+
value: function pause(pauseName) {
|
|
112
|
+
if (this.pauses.size === 0) {
|
|
113
|
+
this.periodMeasurements[this.state].duration = this.periodMeasurements[this.state].duration + (performance.now() - this.currentPeriodStart);
|
|
114
|
+
var _iterator2 = _createForOfIteratorHelper(this.session.insm.periodMeasurers),
|
|
115
|
+
_step2;
|
|
116
|
+
try {
|
|
117
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
118
|
+
var periodMeasurer = _step2.value;
|
|
119
|
+
periodMeasurer.pause();
|
|
120
|
+
}
|
|
121
|
+
} catch (err) {
|
|
122
|
+
_iterator2.e(err);
|
|
123
|
+
} finally {
|
|
124
|
+
_iterator2.f();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
this.pauses.add(pauseName);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Releases a pause for a key.
|
|
132
|
+
*
|
|
133
|
+
* **NOTE**: The session will only resume if this was the only
|
|
134
|
+
* currently tracked pause key.
|
|
135
|
+
*/
|
|
136
|
+
}, {
|
|
137
|
+
key: "resume",
|
|
138
|
+
value: function resume(pauseName) {
|
|
139
|
+
this.pauses.delete(pauseName);
|
|
140
|
+
if (this.pauses.size === 0) {
|
|
141
|
+
this.currentPeriodStart = performance.now();
|
|
142
|
+
var _iterator3 = _createForOfIteratorHelper(this.session.insm.periodMeasurers),
|
|
143
|
+
_step3;
|
|
144
|
+
try {
|
|
145
|
+
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
|
|
146
|
+
var periodMeasurer = _step3.value;
|
|
147
|
+
periodMeasurer.resume();
|
|
148
|
+
}
|
|
149
|
+
} catch (err) {
|
|
150
|
+
_iterator3.e(err);
|
|
151
|
+
} finally {
|
|
152
|
+
_iterator3.f();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}, {
|
|
157
|
+
key: "endResults",
|
|
158
|
+
get: function get() {
|
|
159
|
+
this.changePeriodAndTrackLast(this.state);
|
|
160
|
+
return this.periodMeasurements;
|
|
161
|
+
}
|
|
162
|
+
}, {
|
|
163
|
+
key: "setupActiveStartInteractionListeners",
|
|
164
|
+
value: function setupActiveStartInteractionListeners() {
|
|
165
|
+
var _this = this;
|
|
166
|
+
var events = ['mousemove', 'pointerdown', 'pointerup', 'click', 'keydown', 'keyup', 'scroll'];
|
|
167
|
+
for (var _i = 0, _events = events; _i < _events.length; _i++) {
|
|
168
|
+
var event = _events[_i];
|
|
169
|
+
var eventListener = function eventListener() {
|
|
170
|
+
// start event
|
|
171
|
+
_this.changePeriodAndTrackLast('inactive', 'active');
|
|
172
|
+
};
|
|
173
|
+
window.addEventListener(event, eventListener, {
|
|
174
|
+
once: true
|
|
175
|
+
});
|
|
176
|
+
this.activeStartListeners.push([event, eventListener]);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}, {
|
|
180
|
+
key: "setupEndActiveInteractionListeners",
|
|
181
|
+
value: function setupEndActiveInteractionListeners() {
|
|
182
|
+
var _this2 = this;
|
|
183
|
+
this.activeEndCountDownVisibilityListener = function () {
|
|
184
|
+
if (document.visibilityState === 'hidden') {
|
|
185
|
+
endSession();
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
window.addEventListener('visibilitychange', this.activeEndCountDownVisibilityListener);
|
|
189
|
+
var events = ['mousemove', 'pointerdown', 'pointerup', 'click', 'keydown', 'keyup', 'scroll'];
|
|
190
|
+
for (var _i2 = 0, _events2 = events; _i2 < _events2.length; _i2++) {
|
|
191
|
+
var event = _events2[_i2];
|
|
192
|
+
var eventListener = function eventListener() {
|
|
193
|
+
_this2.activeEndCountDownAbortController.abort();
|
|
194
|
+
_this2.activeEndCountDownAbortController = new AbortController();
|
|
195
|
+
startPeriodEndCountDown(_this2.activeEndCountDownAbortController.signal, function () {
|
|
196
|
+
endSession();
|
|
197
|
+
});
|
|
198
|
+
};
|
|
199
|
+
window.addEventListener(event, eventListener);
|
|
200
|
+
this.activeEndListeners.push([event, eventListener]);
|
|
201
|
+
}
|
|
202
|
+
var endSession = function endSession() {
|
|
203
|
+
_this2.activeEndCountDownAbortController.abort();
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
205
|
+
window.removeEventListener('visibilitychange', _this2.activeEndCountDownVisibilityListener);
|
|
206
|
+
var _iterator4 = _createForOfIteratorHelper(_this2.activeEndListeners),
|
|
207
|
+
_step4;
|
|
208
|
+
try {
|
|
209
|
+
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
|
|
210
|
+
var activeEndListener = _step4.value;
|
|
211
|
+
window.removeEventListener(activeEndListener[0], activeEndListener[1]);
|
|
212
|
+
}
|
|
213
|
+
} catch (err) {
|
|
214
|
+
_iterator4.e(err);
|
|
215
|
+
} finally {
|
|
216
|
+
_iterator4.f();
|
|
217
|
+
}
|
|
218
|
+
_this2.changePeriodAndTrackLast('active', 'inactive');
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// When first setting up -- there has just been an interaction -- so we start a countdown
|
|
222
|
+
this.activeEndCountDownAbortController.abort();
|
|
223
|
+
this.activeEndCountDownAbortController = new AbortController();
|
|
224
|
+
startPeriodEndCountDown(this.activeEndCountDownAbortController.signal, function () {
|
|
225
|
+
endSession();
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
}, {
|
|
229
|
+
key: "changePeriodAndTrackLast",
|
|
230
|
+
value: function changePeriodAndTrackLast(lastPeriod, newPeriod) {
|
|
231
|
+
var _this$activeEndCountD,
|
|
232
|
+
_this3 = this;
|
|
233
|
+
this.periodMeasurements[lastPeriod].duration = this.periodMeasurements[lastPeriod].duration + (performance.now() - this.currentPeriodStart);
|
|
234
|
+
this.periodMeasurements[lastPeriod].count++;
|
|
235
|
+
var interactivityMeasuresPaused = this.latestHeavyTasks.size !== 0;
|
|
236
|
+
var _iterator5 = _createForOfIteratorHelper(this.session.insm.periodMeasurers),
|
|
237
|
+
_step5;
|
|
238
|
+
try {
|
|
239
|
+
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
|
|
240
|
+
var interactivityMeasure = _step5.value;
|
|
241
|
+
var finalResult = newPeriod ? interactivityMeasure.start(interactivityMeasuresPaused) : interactivityMeasure.end();
|
|
242
|
+
var tracked = this.periodMeasurements[lastPeriod].measurements[interactivityMeasure.name];
|
|
243
|
+
if (finalResult.average === 0) {
|
|
244
|
+
// In this case -- we haven't had any measurements complete since last measurement
|
|
245
|
+
// so we do nothing
|
|
246
|
+
} else if (tracked.average === 0) {
|
|
247
|
+
// In this case -- we haven't had any entries come through yet - so we replace any existing entries
|
|
248
|
+
this.periodMeasurements[lastPeriod].measurements[interactivityMeasure.name] = finalResult;
|
|
249
|
+
} else {
|
|
250
|
+
// In this case there is a new measurement which we merge with the previous measurement
|
|
251
|
+
var merged = {
|
|
252
|
+
numerator: finalResult.numerator + tracked.numerator,
|
|
253
|
+
denominator: finalResult.denominator + tracked.denominator,
|
|
254
|
+
average: (finalResult.numerator + tracked.numerator) / (finalResult.denominator + tracked.denominator),
|
|
255
|
+
max: tracked.max === 0 || finalResult.max > tracked.max ? finalResult.max : tracked.max,
|
|
256
|
+
min: tracked.min === 0 || finalResult.min < tracked.min ? finalResult.min : tracked.min
|
|
257
|
+
};
|
|
258
|
+
this.periodMeasurements[lastPeriod].measurements[interactivityMeasure.name] = merged;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
} catch (err) {
|
|
262
|
+
_iterator5.e(err);
|
|
263
|
+
} finally {
|
|
264
|
+
_iterator5.f();
|
|
265
|
+
}
|
|
266
|
+
var _iterator6 = _createForOfIteratorHelper(this.activeStartListeners),
|
|
267
|
+
_step6;
|
|
268
|
+
try {
|
|
269
|
+
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
|
|
270
|
+
var listener = _step6.value;
|
|
271
|
+
window.removeEventListener(listener[0], listener[1]);
|
|
272
|
+
}
|
|
273
|
+
} catch (err) {
|
|
274
|
+
_iterator6.e(err);
|
|
275
|
+
} finally {
|
|
276
|
+
_iterator6.f();
|
|
277
|
+
}
|
|
278
|
+
var _iterator7 = _createForOfIteratorHelper(this.activeEndListeners),
|
|
279
|
+
_step7;
|
|
280
|
+
try {
|
|
281
|
+
for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
|
|
282
|
+
var _listener = _step7.value;
|
|
283
|
+
window.removeEventListener(_listener[0], _listener[1]);
|
|
284
|
+
}
|
|
285
|
+
} catch (err) {
|
|
286
|
+
_iterator7.e(err);
|
|
287
|
+
} finally {
|
|
288
|
+
_iterator7.f();
|
|
289
|
+
}
|
|
290
|
+
(_this$activeEndCountD = this.activeEndCountDownAbortController) === null || _this$activeEndCountD === void 0 || _this$activeEndCountD.abort();
|
|
291
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
292
|
+
window.removeEventListener('visibilitychange', this.activeEndCountDownVisibilityListener);
|
|
293
|
+
if (newPeriod) {
|
|
294
|
+
this.latestPeriodFeatures = new Set(this.session.runningFeatures);
|
|
295
|
+
this.session.runningFeatures.forEach(function (featureName) {
|
|
296
|
+
_this3.periodMeasurements[newPeriod].features.add(featureName);
|
|
297
|
+
});
|
|
298
|
+
this.latestHeavyTasks = new Set(this.session.insm.runningHeavyTasks);
|
|
299
|
+
this.currentPeriodStart = performance.now();
|
|
300
|
+
switch (newPeriod) {
|
|
301
|
+
case 'active':
|
|
302
|
+
this.setupEndActiveInteractionListeners();
|
|
303
|
+
this.state = 'active';
|
|
304
|
+
break;
|
|
305
|
+
case 'inactive':
|
|
306
|
+
this.setupActiveStartInteractionListeners();
|
|
307
|
+
this.state = 'inactive';
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
}]);
|
|
313
|
+
}();
|
|
314
|
+
function startPeriodEndCountDown(signal, handleEnd) {
|
|
315
|
+
var animationFramesSinceLastInteraction = 0;
|
|
316
|
+
var inactiveTimeReached = false;
|
|
317
|
+
var timer;
|
|
318
|
+
var animationFrameHandler;
|
|
319
|
+
var _monitorAnimationFrames = function monitorAnimationFrames() {
|
|
320
|
+
animationFrameHandler = requestAnimationFrame(function () {
|
|
321
|
+
animationFramesSinceLastInteraction++;
|
|
322
|
+
if (animationFramesSinceLastInteraction < 3) {
|
|
323
|
+
_monitorAnimationFrames();
|
|
324
|
+
} else {
|
|
325
|
+
if (inactiveTimeReached) {
|
|
326
|
+
handleEnd();
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
};
|
|
331
|
+
var monitorTime = function monitorTime() {
|
|
332
|
+
timer = setTimeout(function () {
|
|
333
|
+
inactiveTimeReached = true;
|
|
334
|
+
if (animationFramesSinceLastInteraction === 3) {
|
|
335
|
+
handleEnd();
|
|
336
|
+
}
|
|
337
|
+
}, 3000);
|
|
338
|
+
};
|
|
339
|
+
monitorTime();
|
|
340
|
+
_monitorAnimationFrames();
|
|
341
|
+
signal.addEventListener('abort', function () {
|
|
342
|
+
clearTimeout(timer);
|
|
343
|
+
cancelAnimationFrame(animationFrameHandler);
|
|
344
|
+
});
|
|
345
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.INSMSession = void 0;
|
|
8
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
+
var _insmPeriod = require("./insm-period");
|
|
12
|
+
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
13
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2.default)(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
14
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
15
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
16
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
17
|
+
/**
|
|
18
|
+
* Only intended for internal use.
|
|
19
|
+
*
|
|
20
|
+
* Exported for consumers who may require the type.
|
|
21
|
+
*/
|
|
22
|
+
var INSMSession = exports.INSMSession = /*#__PURE__*/function () {
|
|
23
|
+
function INSMSession(experienceKey, experienceProperties, insm) {
|
|
24
|
+
(0, _classCallCheck2.default)(this, INSMSession);
|
|
25
|
+
(0, _defineProperty2.default)(this, "startedAt", performance.now());
|
|
26
|
+
(0, _defineProperty2.default)(this, "running", true);
|
|
27
|
+
(0, _defineProperty2.default)(this, "addedProperties", []);
|
|
28
|
+
(0, _defineProperty2.default)(this, "runningFeatures", new Set());
|
|
29
|
+
this.experienceKey = experienceKey;
|
|
30
|
+
this.experienceProperties = experienceProperties;
|
|
31
|
+
this.insm = insm;
|
|
32
|
+
this.periodTracking = new _insmPeriod.PeriodTracking(this);
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Note: Events are not reliably fired from mobile browsers (ie. when a browser is closed when not in use)
|
|
36
|
+
*/
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Adds a feature to the currently running session
|
|
41
|
+
*/
|
|
42
|
+
return (0, _createClass2.default)(INSMSession, [{
|
|
43
|
+
key: "startFeature",
|
|
44
|
+
value: function startFeature(featureName) {
|
|
45
|
+
var _this$periodTracking;
|
|
46
|
+
this.runningFeatures.add(featureName);
|
|
47
|
+
(_this$periodTracking = this.periodTracking) === null || _this$periodTracking === void 0 || _this$periodTracking.startFeature(featureName);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Ends a features usage in the currently running session
|
|
52
|
+
*/
|
|
53
|
+
}, {
|
|
54
|
+
key: "endFeature",
|
|
55
|
+
value: function endFeature(featureName) {
|
|
56
|
+
this.runningFeatures.delete(featureName);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Returns details on the current session.
|
|
61
|
+
*/
|
|
62
|
+
}, {
|
|
63
|
+
key: "details",
|
|
64
|
+
get: function get() {
|
|
65
|
+
return {
|
|
66
|
+
experienceKey: this.experienceKey,
|
|
67
|
+
experienceProperties: this.experienceProperties,
|
|
68
|
+
paused: this.periodTracking.pauses.size > 0,
|
|
69
|
+
periodState: this.periodTracking.state,
|
|
70
|
+
/**
|
|
71
|
+
* The only scenario where this value should return false is when
|
|
72
|
+
* the experience has been stopped early.
|
|
73
|
+
*/
|
|
74
|
+
running: this.running
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* This api takes either a static single-level key-value object, or callbacks which return the same and
|
|
80
|
+
* will be evaluated on session end.
|
|
81
|
+
*
|
|
82
|
+
* When ending a session, all properties received via this api are merged, in order, into the resulting
|
|
83
|
+
* insm event’s properties; last write wins.
|
|
84
|
+
*
|
|
85
|
+
* Callback values are evaluated at session end.
|
|
86
|
+
*
|
|
87
|
+
* For example, for the following
|
|
88
|
+
*
|
|
89
|
+
* ```ts
|
|
90
|
+
* insm.experience.addProperties({ one: 1, two: 2 });
|
|
91
|
+
* insm.experience.addProperties(() => ({ one: 'one' }));
|
|
92
|
+
* insm.experience.addProperties({ three: 3 });
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* The resulting added properties will be
|
|
96
|
+
*
|
|
97
|
+
* ```ts
|
|
98
|
+
* { one: 'one', two: 2, three: 3 }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
}, {
|
|
102
|
+
key: "addProperties",
|
|
103
|
+
value: function addProperties(propertiesToAdd) {
|
|
104
|
+
this.addedProperties.push(propertiesToAdd);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* In some scenarios (ie. when a page error boundary is hit), you will want to exit early.
|
|
109
|
+
* This is api supports these scenarios
|
|
110
|
+
*
|
|
111
|
+
* ```ts
|
|
112
|
+
* insm.stopEarly(reasonKey: string, description: string);
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* Sessions closed early are identifiable by their end details
|
|
116
|
+
* `"endDetails": { stoppedBy: "early-stop", reasonKey, description }`.
|
|
117
|
+
*
|
|
118
|
+
* **Note**: The session is ended as soon as this is called, and any `addProperties` handlers will
|
|
119
|
+
* called immediately.
|
|
120
|
+
*/
|
|
121
|
+
}, {
|
|
122
|
+
key: "earlyStop",
|
|
123
|
+
value: function earlyStop(reason, description) {
|
|
124
|
+
this.end({
|
|
125
|
+
stoppedBy: 'early-stop',
|
|
126
|
+
reason: reason,
|
|
127
|
+
description: description
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}, {
|
|
131
|
+
key: "end",
|
|
132
|
+
value: function end(endDetails) {
|
|
133
|
+
var _this$insm$analyticsW;
|
|
134
|
+
if (this.running === false) {
|
|
135
|
+
// If an experience has already been ended -- don't repeat the ending
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
this.running = false;
|
|
139
|
+
var endedAt = performance.now();
|
|
140
|
+
var duration = endedAt - this.startedAt;
|
|
141
|
+
var evaluatedAddedProperties = {};
|
|
142
|
+
var _iterator = _createForOfIteratorHelper(this.addedProperties),
|
|
143
|
+
_step;
|
|
144
|
+
try {
|
|
145
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
146
|
+
var addedProperty = _step.value;
|
|
147
|
+
if (typeof addedProperty === 'function') {
|
|
148
|
+
Object.assign(evaluatedAddedProperties, addedProperty());
|
|
149
|
+
} else {
|
|
150
|
+
Object.assign(evaluatedAddedProperties, addedProperty);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
} catch (err) {
|
|
154
|
+
_iterator.e(err);
|
|
155
|
+
} finally {
|
|
156
|
+
_iterator.f();
|
|
157
|
+
}
|
|
158
|
+
var periodResults = this.periodTracking.endResults;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* This event ends up as "insm measured"
|
|
162
|
+
*/
|
|
163
|
+
var operationalEvent = {
|
|
164
|
+
actionSubject: 'insm',
|
|
165
|
+
action: 'measured',
|
|
166
|
+
attributes: _objectSpread(_objectSpread({}, evaluatedAddedProperties), {}, {
|
|
167
|
+
experienceKey: this.experienceKey,
|
|
168
|
+
initial: this.experienceProperties.initial,
|
|
169
|
+
contentId: this.experienceProperties.contentId,
|
|
170
|
+
timing: {
|
|
171
|
+
startedAt: this.startedAt,
|
|
172
|
+
duration: duration
|
|
173
|
+
},
|
|
174
|
+
periods: periodResults,
|
|
175
|
+
endDetails: endDetails
|
|
176
|
+
}),
|
|
177
|
+
tags: ['insm'],
|
|
178
|
+
source: 'insm'
|
|
179
|
+
};
|
|
180
|
+
(_this$insm$analyticsW = this.insm.analyticsWebClient) === null || _this$insm$analyticsW === void 0 || _this$insm$analyticsW.sendOperationalEvent(operationalEvent);
|
|
181
|
+
}
|
|
182
|
+
}]);
|
|
183
|
+
}();
|
package/dist/cjs/insm.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.INSM = void 0;
|
|
8
|
+
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
|
|
9
|
+
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
|
|
10
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
11
|
+
var _insmSession = require("./insm-session");
|
|
12
|
+
var _afps = require("./period-measurers/afps");
|
|
13
|
+
var _inp = require("./inp-measurers/inp");
|
|
14
|
+
var INSM = exports.INSM = /*#__PURE__*/function () {
|
|
15
|
+
function INSM(options) {
|
|
16
|
+
var _this = this;
|
|
17
|
+
(0, _classCallCheck2.default)(this, INSM);
|
|
18
|
+
/**
|
|
19
|
+
* Heavy tasks are tracked at the insm layer as heavy tasks
|
|
20
|
+
* are expected at times to be unrelated to the current
|
|
21
|
+
* page session.
|
|
22
|
+
*/
|
|
23
|
+
(0, _defineProperty2.default)(this, "runningHeavyTasks", new Set());
|
|
24
|
+
this.periodMeasurers = [new _afps.AnimationFPSIM(), new _inp.INPTracker(), new _inp.INPTracker({
|
|
25
|
+
includedInteractions: ['pointerup']
|
|
26
|
+
}), new _inp.INPTracker({
|
|
27
|
+
includedInteractions: ['pointerdown']
|
|
28
|
+
}), new _inp.INPTracker({
|
|
29
|
+
includedInteractions: ['click']
|
|
30
|
+
}), new _inp.INPTracker({
|
|
31
|
+
includedInteractions: ['keydown']
|
|
32
|
+
}), new _inp.INPTracker({
|
|
33
|
+
includedInteractions: ['keyup']
|
|
34
|
+
})];
|
|
35
|
+
this.options = options;
|
|
36
|
+
|
|
37
|
+
// If this does throw -- we do want an unhandledRejection rejection to be passed to the window
|
|
38
|
+
// this is to ease debugging.
|
|
39
|
+
options.getAnalyticsWebClient.then(function (analyticsWebClient) {
|
|
40
|
+
return _this.analyticsWebClient = analyticsWebClient;
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// No cleanup needs to be performed -- as this is intended to run until the tab is closed
|
|
44
|
+
// eslint-disable-next-line @repo/internal/dom-events/no-unsafe-event-listeners
|
|
45
|
+
window.addEventListener('pagehide', function () {
|
|
46
|
+
var _this$runningSession;
|
|
47
|
+
(_this$runningSession = _this.runningSession) === null || _this$runningSession === void 0 || _this$runningSession.end({
|
|
48
|
+
stoppedBy: 'pagehide'
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Starts a heavy task in the currently running session.
|
|
55
|
+
*
|
|
56
|
+
* This also pauses measurement.
|
|
57
|
+
*/
|
|
58
|
+
return (0, _createClass2.default)(INSM, [{
|
|
59
|
+
key: "startHeavyTask",
|
|
60
|
+
value: function startHeavyTask(heavyTaskName) {
|
|
61
|
+
var _this$runningSession2, _this$runningSession3;
|
|
62
|
+
this.runningHeavyTasks.add(heavyTaskName);
|
|
63
|
+
(_this$runningSession2 = this.runningSession) === null || _this$runningSession2 === void 0 || (_this$runningSession2 = _this$runningSession2.periodTracking) === null || _this$runningSession2 === void 0 || _this$runningSession2.startHeavyTask(heavyTaskName);
|
|
64
|
+
(_this$runningSession3 = this.runningSession) === null || _this$runningSession3 === void 0 || _this$runningSession3.periodTracking.pause(heavyTaskName);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Ends a heavy task in the currently running session
|
|
69
|
+
*/
|
|
70
|
+
}, {
|
|
71
|
+
key: "endHeavyTask",
|
|
72
|
+
value: function endHeavyTask(heavyTaskName) {
|
|
73
|
+
var _this$runningSession4;
|
|
74
|
+
this.runningHeavyTasks.delete(heavyTaskName);
|
|
75
|
+
(_this$runningSession4 = this.runningSession) === null || _this$runningSession4 === void 0 || _this$runningSession4.periodTracking.resume(heavyTaskName);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Call this when starting a new experience. This is expected to be wired to the product
|
|
80
|
+
* routing solution.
|
|
81
|
+
*
|
|
82
|
+
* It's expected this call will be paired with a `insm.session.startHeavyTask('page-load')` and subsequent `insm.session.endHeavyTask('page-load')`
|
|
83
|
+
* so that performance degradations linked to the page initialisation are excluded from the active interactivity monitoring.
|
|
84
|
+
*
|
|
85
|
+
*
|
|
86
|
+
* ```ts
|
|
87
|
+
* insm.start('edit-page', { initial: true, contentId: '9001' })
|
|
88
|
+
* insm.session.startHeavyTask(''page-load')
|
|
89
|
+
* // ... heavy initialisation work
|
|
90
|
+
* insm.session.endHeavyTask(''page-load')
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
}, {
|
|
94
|
+
key: "start",
|
|
95
|
+
value: function start(experienceKey, experienceProperties) {
|
|
96
|
+
var _this$options$experie;
|
|
97
|
+
if (this.runningSession !== undefined) {
|
|
98
|
+
this.runningSession.end({
|
|
99
|
+
stoppedBy: 'new-experience',
|
|
100
|
+
experienceKey: experienceKey,
|
|
101
|
+
contentId: experienceProperties.contentId
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
if ((_this$options$experie = this.options.experiences[experienceKey]) !== null && _this$options$experie !== void 0 && _this$options$experie.enabled) {
|
|
105
|
+
this.runningSession = new _insmSession.INSMSession(experienceKey, experienceProperties, this);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* This prematurely halts any running experience measurement. It's expected to be used in
|
|
111
|
+
* scenarios such as when error boundaries are hit.
|
|
112
|
+
*/
|
|
113
|
+
}, {
|
|
114
|
+
key: "stopEarly",
|
|
115
|
+
value: function stopEarly(reasonKey, description) {
|
|
116
|
+
var _this$runningSession5;
|
|
117
|
+
(_this$runningSession5 = this.runningSession) === null || _this$runningSession5 === void 0 || _this$runningSession5.earlyStop(reasonKey, description);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Gets the current running session details
|
|
122
|
+
*/
|
|
123
|
+
}, {
|
|
124
|
+
key: "session",
|
|
125
|
+
get: function get() {
|
|
126
|
+
return this.runningSession;
|
|
127
|
+
}
|
|
128
|
+
}]);
|
|
129
|
+
}();
|