@elliemae/pui-app-sdk 5.13.5 → 5.14.0
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/dist/cjs/utils/headSampler.js +70 -0
- package/dist/cjs/utils/micro-frontend/host.js +1 -1
- package/dist/cjs/utils/micro-frontend/scripting-objects/analytics.js +38 -7
- package/dist/esm/utils/headSampler.js +50 -0
- package/dist/esm/utils/micro-frontend/host.js +1 -1
- package/dist/esm/utils/micro-frontend/scripting-objects/analytics.js +38 -7
- package/dist/types/lib/utils/headSampler.d.ts +16 -0
- package/dist/types/lib/utils/micro-frontend/host.d.ts +3 -2
- package/dist/types/lib/utils/micro-frontend/scripting-objects/analytics.d.ts +18 -2
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +33 -33
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var headSampler_exports = {};
|
|
20
|
+
__export(headSampler_exports, {
|
|
21
|
+
HeadSampler: () => HeadSampler
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(headSampler_exports);
|
|
24
|
+
const normalize = (percent) => {
|
|
25
|
+
if (typeof percent !== "number" || Number.isNaN(percent)) return 0;
|
|
26
|
+
if (percent >= 100) return 100;
|
|
27
|
+
if (percent <= 0) return 0;
|
|
28
|
+
return percent;
|
|
29
|
+
};
|
|
30
|
+
const convertToDivisibleBy5 = (percent) => Math.round(normalize(percent) / 5) * 5;
|
|
31
|
+
const percentToFraction = (percent) => {
|
|
32
|
+
const numerator = percent;
|
|
33
|
+
const denominator = 100;
|
|
34
|
+
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
|
|
35
|
+
const divisor = gcd(numerator, denominator);
|
|
36
|
+
return { numerator: numerator / divisor, denominator: denominator / divisor };
|
|
37
|
+
};
|
|
38
|
+
class HeadSampler {
|
|
39
|
+
/**
|
|
40
|
+
* Upper bound of the sampling size
|
|
41
|
+
*/
|
|
42
|
+
#upperBound = 0;
|
|
43
|
+
/**
|
|
44
|
+
* Total size of the sampling
|
|
45
|
+
*/
|
|
46
|
+
#totalSize = 0;
|
|
47
|
+
/**
|
|
48
|
+
* Number of events sampled
|
|
49
|
+
*/
|
|
50
|
+
#sampled = 0;
|
|
51
|
+
/**
|
|
52
|
+
* Creates new instance of HeadSampler
|
|
53
|
+
* @param samplingPercent sampling percentage
|
|
54
|
+
*/
|
|
55
|
+
constructor(samplingPercent) {
|
|
56
|
+
const value = percentToFraction(convertToDivisibleBy5(samplingPercent));
|
|
57
|
+
this.#upperBound = value.numerator;
|
|
58
|
+
this.#totalSize = value.denominator;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* check if the event should be sampled
|
|
62
|
+
* @returns true if the event should be sampled
|
|
63
|
+
*/
|
|
64
|
+
shouldSample = () => {
|
|
65
|
+
this.#sampled += 1;
|
|
66
|
+
if (this.#sampled <= this.#upperBound) return true;
|
|
67
|
+
if (this.#sampled === this.#totalSize) this.#sampled = 0;
|
|
68
|
+
return false;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
@@ -62,7 +62,7 @@ class CMicroAppHost {
|
|
|
62
62
|
};
|
|
63
63
|
this.activeGuests = {};
|
|
64
64
|
this.#ssfHostRef = params?.ssfHostRef || null;
|
|
65
|
-
const analyticsObj = params?.analytics ?? new import_analytics.Analytics(this.logger);
|
|
65
|
+
const analyticsObj = params?.analytics ?? new import_analytics.Analytics({ logger: this.logger });
|
|
66
66
|
this.scriptingObjects = {
|
|
67
67
|
analytics: analyticsObj,
|
|
68
68
|
...params?.scriptingObjects ?? {}
|
|
@@ -34,20 +34,41 @@ module.exports = __toCommonJS(analytics_exports);
|
|
|
34
34
|
var import_em_ssf_host = __toESM(require("@elliemae/em-ssf-host"));
|
|
35
35
|
var import_web_analytics = require("./web-analytics.js");
|
|
36
36
|
var import_helpers = require("../../helpers.js");
|
|
37
|
+
var import_headSampler = require("../../headSampler.js");
|
|
37
38
|
class Analytics extends import_em_ssf_host.default.ScriptingObject {
|
|
38
39
|
/**
|
|
39
40
|
* logger instance
|
|
40
41
|
*/
|
|
41
42
|
#logger;
|
|
43
|
+
/**
|
|
44
|
+
* sampling size for different events
|
|
45
|
+
*/
|
|
46
|
+
#samplingSizes = {};
|
|
42
47
|
/**
|
|
43
48
|
* Creates new instance of Analytics scripting object
|
|
44
|
-
* @param
|
|
49
|
+
* @param params Analytics constructor parameters
|
|
45
50
|
*/
|
|
46
|
-
constructor(
|
|
51
|
+
constructor(params) {
|
|
47
52
|
super("analytics");
|
|
48
|
-
this.#logger = logger;
|
|
53
|
+
this.#logger = params.logger;
|
|
54
|
+
this.#setupSampling(params.samplingRatios);
|
|
49
55
|
this.#monitorPerformance();
|
|
50
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* setup sampling size for different events
|
|
59
|
+
* @param samplingSizes sampling sizes for different events
|
|
60
|
+
*/
|
|
61
|
+
#setupSampling = (samplingSizes = {}) => {
|
|
62
|
+
Object.keys(samplingSizes).forEach((key) => {
|
|
63
|
+
this.#samplingSizes[key] = new import_headSampler.HeadSampler(samplingSizes[key]);
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* check if the event should be sampled and recorded
|
|
68
|
+
* @param name name of the event
|
|
69
|
+
* @returns true if the event should be sampled and recorded
|
|
70
|
+
*/
|
|
71
|
+
#shouldSampleandRecord = (name) => this.#samplingSizes[name] ? this.#samplingSizes[name].shouldSample() : true;
|
|
51
72
|
/**
|
|
52
73
|
* monitor performance and report to GTM
|
|
53
74
|
*/
|
|
@@ -57,18 +78,28 @@ class Analytics extends import_em_ssf_host.default.ScriptingObject {
|
|
|
57
78
|
for (const entry of list.getEntries()) {
|
|
58
79
|
switch (entry.entryType) {
|
|
59
80
|
case "measure": {
|
|
81
|
+
if (!this.#shouldSampleandRecord(entry.name)) return;
|
|
60
82
|
const detail = entry.detail ?? {};
|
|
83
|
+
const duration = entry.duration.toString();
|
|
84
|
+
const startTime = new Date(
|
|
85
|
+
performance.timeOrigin + entry.startTime
|
|
86
|
+
).toISOString();
|
|
61
87
|
this.sendBAEvent({
|
|
62
88
|
event: "timing",
|
|
63
89
|
name: entry.name,
|
|
64
|
-
duration
|
|
65
|
-
startTime
|
|
66
|
-
performance.timeOrigin + entry.startTime
|
|
67
|
-
).toISOString(),
|
|
90
|
+
duration,
|
|
91
|
+
startTime,
|
|
68
92
|
...(0, import_web_analytics.getBAEventParameters)(),
|
|
69
93
|
...detail
|
|
70
94
|
}).catch(() => {
|
|
71
95
|
});
|
|
96
|
+
this.#logger.info({
|
|
97
|
+
message: "timing",
|
|
98
|
+
event: entry.name,
|
|
99
|
+
duration,
|
|
100
|
+
startTime,
|
|
101
|
+
detail
|
|
102
|
+
});
|
|
72
103
|
break;
|
|
73
104
|
}
|
|
74
105
|
default:
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const normalize = (percent) => {
|
|
2
|
+
if (typeof percent !== "number" || Number.isNaN(percent)) return 0;
|
|
3
|
+
if (percent >= 100) return 100;
|
|
4
|
+
if (percent <= 0) return 0;
|
|
5
|
+
return percent;
|
|
6
|
+
};
|
|
7
|
+
const convertToDivisibleBy5 = (percent) => Math.round(normalize(percent) / 5) * 5;
|
|
8
|
+
const percentToFraction = (percent) => {
|
|
9
|
+
const numerator = percent;
|
|
10
|
+
const denominator = 100;
|
|
11
|
+
const gcd = (a, b) => b === 0 ? a : gcd(b, a % b);
|
|
12
|
+
const divisor = gcd(numerator, denominator);
|
|
13
|
+
return { numerator: numerator / divisor, denominator: denominator / divisor };
|
|
14
|
+
};
|
|
15
|
+
class HeadSampler {
|
|
16
|
+
/**
|
|
17
|
+
* Upper bound of the sampling size
|
|
18
|
+
*/
|
|
19
|
+
#upperBound = 0;
|
|
20
|
+
/**
|
|
21
|
+
* Total size of the sampling
|
|
22
|
+
*/
|
|
23
|
+
#totalSize = 0;
|
|
24
|
+
/**
|
|
25
|
+
* Number of events sampled
|
|
26
|
+
*/
|
|
27
|
+
#sampled = 0;
|
|
28
|
+
/**
|
|
29
|
+
* Creates new instance of HeadSampler
|
|
30
|
+
* @param samplingPercent sampling percentage
|
|
31
|
+
*/
|
|
32
|
+
constructor(samplingPercent) {
|
|
33
|
+
const value = percentToFraction(convertToDivisibleBy5(samplingPercent));
|
|
34
|
+
this.#upperBound = value.numerator;
|
|
35
|
+
this.#totalSize = value.denominator;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* check if the event should be sampled
|
|
39
|
+
* @returns true if the event should be sampled
|
|
40
|
+
*/
|
|
41
|
+
shouldSample = () => {
|
|
42
|
+
this.#sampled += 1;
|
|
43
|
+
if (this.#sampled <= this.#upperBound) return true;
|
|
44
|
+
if (this.#sampled === this.#totalSize) this.#sampled = 0;
|
|
45
|
+
return false;
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
HeadSampler
|
|
50
|
+
};
|
|
@@ -46,7 +46,7 @@ class CMicroAppHost {
|
|
|
46
46
|
};
|
|
47
47
|
this.activeGuests = {};
|
|
48
48
|
this.#ssfHostRef = params?.ssfHostRef || null;
|
|
49
|
-
const analyticsObj = params?.analytics ?? new Analytics(this.logger);
|
|
49
|
+
const analyticsObj = params?.analytics ?? new Analytics({ logger: this.logger });
|
|
50
50
|
this.scriptingObjects = {
|
|
51
51
|
analytics: analyticsObj,
|
|
52
52
|
...params?.scriptingObjects ?? {}
|
|
@@ -1,20 +1,41 @@
|
|
|
1
1
|
import ssfHost from "@elliemae/em-ssf-host";
|
|
2
2
|
import { getBAEventParameters } from "./web-analytics.js";
|
|
3
3
|
import { getProductAppDetails } from "../../helpers.js";
|
|
4
|
+
import { HeadSampler } from "../../headSampler.js";
|
|
4
5
|
class Analytics extends ssfHost.ScriptingObject {
|
|
5
6
|
/**
|
|
6
7
|
* logger instance
|
|
7
8
|
*/
|
|
8
9
|
#logger;
|
|
10
|
+
/**
|
|
11
|
+
* sampling size for different events
|
|
12
|
+
*/
|
|
13
|
+
#samplingSizes = {};
|
|
9
14
|
/**
|
|
10
15
|
* Creates new instance of Analytics scripting object
|
|
11
|
-
* @param
|
|
16
|
+
* @param params Analytics constructor parameters
|
|
12
17
|
*/
|
|
13
|
-
constructor(
|
|
18
|
+
constructor(params) {
|
|
14
19
|
super("analytics");
|
|
15
|
-
this.#logger = logger;
|
|
20
|
+
this.#logger = params.logger;
|
|
21
|
+
this.#setupSampling(params.samplingRatios);
|
|
16
22
|
this.#monitorPerformance();
|
|
17
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* setup sampling size for different events
|
|
26
|
+
* @param samplingSizes sampling sizes for different events
|
|
27
|
+
*/
|
|
28
|
+
#setupSampling = (samplingSizes = {}) => {
|
|
29
|
+
Object.keys(samplingSizes).forEach((key) => {
|
|
30
|
+
this.#samplingSizes[key] = new HeadSampler(samplingSizes[key]);
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* check if the event should be sampled and recorded
|
|
35
|
+
* @param name name of the event
|
|
36
|
+
* @returns true if the event should be sampled and recorded
|
|
37
|
+
*/
|
|
38
|
+
#shouldSampleandRecord = (name) => this.#samplingSizes[name] ? this.#samplingSizes[name].shouldSample() : true;
|
|
18
39
|
/**
|
|
19
40
|
* monitor performance and report to GTM
|
|
20
41
|
*/
|
|
@@ -24,18 +45,28 @@ class Analytics extends ssfHost.ScriptingObject {
|
|
|
24
45
|
for (const entry of list.getEntries()) {
|
|
25
46
|
switch (entry.entryType) {
|
|
26
47
|
case "measure": {
|
|
48
|
+
if (!this.#shouldSampleandRecord(entry.name)) return;
|
|
27
49
|
const detail = entry.detail ?? {};
|
|
50
|
+
const duration = entry.duration.toString();
|
|
51
|
+
const startTime = new Date(
|
|
52
|
+
performance.timeOrigin + entry.startTime
|
|
53
|
+
).toISOString();
|
|
28
54
|
this.sendBAEvent({
|
|
29
55
|
event: "timing",
|
|
30
56
|
name: entry.name,
|
|
31
|
-
duration
|
|
32
|
-
startTime
|
|
33
|
-
performance.timeOrigin + entry.startTime
|
|
34
|
-
).toISOString(),
|
|
57
|
+
duration,
|
|
58
|
+
startTime,
|
|
35
59
|
...getBAEventParameters(),
|
|
36
60
|
...detail
|
|
37
61
|
}).catch(() => {
|
|
38
62
|
});
|
|
63
|
+
this.#logger.info({
|
|
64
|
+
message: "timing",
|
|
65
|
+
event: entry.name,
|
|
66
|
+
duration,
|
|
67
|
+
startTime,
|
|
68
|
+
detail
|
|
69
|
+
});
|
|
39
70
|
break;
|
|
40
71
|
}
|
|
41
72
|
default:
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Samples events based on the sampling size
|
|
3
|
+
*/
|
|
4
|
+
export declare class HeadSampler {
|
|
5
|
+
#private;
|
|
6
|
+
/**
|
|
7
|
+
* Creates new instance of HeadSampler
|
|
8
|
+
* @param samplingPercent sampling percentage
|
|
9
|
+
*/
|
|
10
|
+
constructor(samplingPercent: number);
|
|
11
|
+
/**
|
|
12
|
+
* check if the event should be sampled
|
|
13
|
+
* @returns true if the event should be sampled
|
|
14
|
+
*/
|
|
15
|
+
shouldSample: () => boolean;
|
|
16
|
+
}
|
|
@@ -2,8 +2,9 @@ import { History, To } from 'history';
|
|
|
2
2
|
import { DefaultTheme } from 'styled-components';
|
|
3
3
|
import { IMicroAppHost, ResizeEventHandler, BreakpointChangeEventHandler, SubscriptionListener } from '@elliemae/pui-micro-frontend-base';
|
|
4
4
|
import ssfHost from '@elliemae/em-ssf-host';
|
|
5
|
-
import { BAEvent
|
|
5
|
+
import { BAEvent } from '@elliemae/pui-scripting-object';
|
|
6
6
|
import { MicroFrontEndLogger } from '../types.js';
|
|
7
|
+
import { Analytics } from './scripting-objects/analytics.js';
|
|
7
8
|
type HostOptions = {
|
|
8
9
|
systemVersion: string;
|
|
9
10
|
history: History;
|
|
@@ -19,7 +20,7 @@ type ConstructorParams = {
|
|
|
19
20
|
onRenewSessionTimer?: () => void;
|
|
20
21
|
onInit?: OnInitCallback;
|
|
21
22
|
ssfHostRef?: typeof ssfHost.Host;
|
|
22
|
-
analytics?:
|
|
23
|
+
analytics?: Analytics;
|
|
23
24
|
};
|
|
24
25
|
export declare class CMicroAppHost implements IMicroAppHost {
|
|
25
26
|
#private;
|
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
import ssfHost from '@elliemae/em-ssf-host';
|
|
2
2
|
import { IAnalytics, BAEvent, TimingOptions } from '@elliemae/pui-scripting-object';
|
|
3
3
|
import { MicroFrontEndLogger } from '../../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Analytics constructor parameters
|
|
6
|
+
*/
|
|
7
|
+
type AnalyticsParams = {
|
|
8
|
+
/**
|
|
9
|
+
* logger instance
|
|
10
|
+
*/
|
|
11
|
+
logger: MicroFrontEndLogger;
|
|
12
|
+
/**
|
|
13
|
+
* sampling ratios for different events
|
|
14
|
+
* ratio is a number between 0 and 1
|
|
15
|
+
* @example { 'event1': 0.1, 'event2': 0.5 }
|
|
16
|
+
*/
|
|
17
|
+
samplingRatios?: Record<string, number>;
|
|
18
|
+
};
|
|
4
19
|
/**
|
|
5
20
|
* Analytics scripting object
|
|
6
21
|
*/
|
|
@@ -8,9 +23,9 @@ export declare class Analytics extends ssfHost.ScriptingObject implements IAnaly
|
|
|
8
23
|
#private;
|
|
9
24
|
/**
|
|
10
25
|
* Creates new instance of Analytics scripting object
|
|
11
|
-
* @param
|
|
26
|
+
* @param params Analytics constructor parameters
|
|
12
27
|
*/
|
|
13
|
-
constructor(
|
|
28
|
+
constructor(params: AnalyticsParams);
|
|
14
29
|
/**
|
|
15
30
|
* send business analytics event
|
|
16
31
|
* @param event business analytics event
|
|
@@ -43,3 +58,4 @@ export declare class Analytics extends ssfHost.ScriptingObject implements IAnaly
|
|
|
43
58
|
*/
|
|
44
59
|
endTiming: (start: string | PerformanceMeasure, options: TimingOptions) => Promise<void>;
|
|
45
60
|
}
|
|
61
|
+
export {};
|