@elliemae/ssf-host 2.24.0 → 2.25.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/guest.js +15 -16
- package/dist/cjs/host.js +37 -55
- package/dist/cjs/performanceTracker.js +111 -0
- package/dist/esm/guest.js +15 -16
- package/dist/esm/host.js +37 -55
- package/dist/esm/performanceTracker.js +91 -0
- package/dist/public/callchain-host.html +1 -1
- package/dist/public/callchain-intermediate.html +1 -1
- package/dist/public/e2e-host.html +1 -1
- package/dist/public/e2e-index.html +1 -1
- package/dist/public/index.html +1 -1
- package/dist/public/js/emuiSsfHost.5bb7139d7e86c74f0b6d.js +3 -0
- package/dist/public/js/emuiSsfHost.5bb7139d7e86c74f0b6d.js.br +0 -0
- package/dist/public/js/emuiSsfHost.5bb7139d7e86c74f0b6d.js.gz +0 -0
- package/dist/public/js/emuiSsfHost.5bb7139d7e86c74f0b6d.js.map +1 -0
- package/dist/public/popup-focus-host.html +1 -1
- package/dist/public/utils.js +1 -1
- package/dist/public/utils.js.br +0 -0
- package/dist/public/utils.js.gz +0 -0
- package/dist/public/utils.js.map +1 -1
- package/dist/public/v1-guest-v2-host.html +1 -1
- package/dist/public/v2-host-v1-guest.html +1 -1
- package/dist/types/lib/guest.d.ts +4 -3
- package/dist/types/lib/host.d.ts +0 -1
- package/dist/types/lib/ihost.d.ts +18 -1
- package/dist/types/lib/performanceTracker.d.ts +46 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dist/umd/index.js +1 -1
- package/dist/umd/index.js.br +0 -0
- package/dist/umd/index.js.gz +0 -0
- package/dist/umd/index.js.map +1 -1
- package/dist/umd/utils.js +1 -1
- package/dist/umd/utils.js.br +0 -0
- package/dist/umd/utils.js.gz +0 -0
- package/dist/umd/utils.js.map +1 -1
- package/package.json +4 -4
- package/dist/public/js/emuiSsfHost.071827d0d7e775690fbb.js +0 -3
- package/dist/public/js/emuiSsfHost.071827d0d7e775690fbb.js.br +0 -0
- package/dist/public/js/emuiSsfHost.071827d0d7e775690fbb.js.gz +0 -0
- package/dist/public/js/emuiSsfHost.071827d0d7e775690fbb.js.map +0 -1
package/dist/cjs/guest.js
CHANGED
|
@@ -74,9 +74,9 @@ class Guest {
|
|
|
74
74
|
*/
|
|
75
75
|
#remoting;
|
|
76
76
|
/**
|
|
77
|
-
*
|
|
77
|
+
* performance tracker for timing measurements
|
|
78
78
|
*/
|
|
79
|
-
#
|
|
79
|
+
#perfTracker;
|
|
80
80
|
/**
|
|
81
81
|
* Create object representing guest application
|
|
82
82
|
* @param {GuestOption} option - options for creating a guest application
|
|
@@ -91,7 +91,7 @@ class Guest {
|
|
|
91
91
|
searchParams = {},
|
|
92
92
|
openMode = import_types.OpenMode.Embed,
|
|
93
93
|
remoting,
|
|
94
|
-
|
|
94
|
+
perfTracker
|
|
95
95
|
} = option;
|
|
96
96
|
this.id = guestId;
|
|
97
97
|
this.title = title;
|
|
@@ -102,7 +102,7 @@ class Guest {
|
|
|
102
102
|
this.window = window;
|
|
103
103
|
this.openMode = openMode;
|
|
104
104
|
this.capabilities = {};
|
|
105
|
-
this.#
|
|
105
|
+
this.#perfTracker = perfTracker;
|
|
106
106
|
this.#remoting = remoting;
|
|
107
107
|
}
|
|
108
108
|
/**
|
|
@@ -188,16 +188,17 @@ class Guest {
|
|
|
188
188
|
* invokes event callback on the guest application
|
|
189
189
|
* @param {EventObject} event - event object
|
|
190
190
|
* @param {number} timeout - timeout in milliseconds
|
|
191
|
+
* @returns {Promise} resolves when the guest handles the event
|
|
191
192
|
*/
|
|
192
193
|
dispatchEvent = (event, timeout) => {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
{
|
|
194
|
+
let timingToken;
|
|
195
|
+
if (this.#perfTracker.enabled) {
|
|
196
|
+
const name = `ScriptingObject.Event.${event.object.objectId}.${event.eventName}`;
|
|
197
|
+
timingToken = this.#perfTracker.start(name, {
|
|
196
198
|
appId: this.id,
|
|
197
199
|
appUrl: this.url
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
201
202
|
return this.#remoting.invoke({
|
|
202
203
|
targetWin: this.window,
|
|
203
204
|
targetOrigin: this.origin,
|
|
@@ -205,14 +206,12 @@ class Guest {
|
|
|
205
206
|
messageBody: event,
|
|
206
207
|
responseTimeoutMs: timeout
|
|
207
208
|
}).finally(() => {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
{
|
|
209
|
+
if (timingToken) {
|
|
210
|
+
this.#perfTracker.end(timingToken, {
|
|
211
211
|
appId: this.id,
|
|
212
212
|
appUrl: this.url
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
});
|
|
213
|
+
});
|
|
214
|
+
}
|
|
216
215
|
});
|
|
217
216
|
};
|
|
218
217
|
/**
|
package/dist/cjs/host.js
CHANGED
|
@@ -27,6 +27,7 @@ var import_microfe_common = require("@elliemae/microfe-common");
|
|
|
27
27
|
var import_types = require("./types.js");
|
|
28
28
|
var import_guest = require("./guest.js");
|
|
29
29
|
var import_utils = require("./utils.js");
|
|
30
|
+
var import_performanceTracker = require("./performanceTracker.js");
|
|
30
31
|
const SANDBOX_DEFAULT = [
|
|
31
32
|
import_types.IFrameSandboxValues.AllowScripts,
|
|
32
33
|
import_types.IFrameSandboxValues.AllowPopups,
|
|
@@ -98,16 +99,13 @@ class SSFHost {
|
|
|
98
99
|
*/
|
|
99
100
|
#guestMetadata = /* @__PURE__ */ new Map();
|
|
100
101
|
/**
|
|
101
|
-
*
|
|
102
|
-
* Used to skip redundant startTiming/endTiming cross-window calls for
|
|
103
|
-
* the same API or event within the dedup window.
|
|
102
|
+
* Performance tracker for host-side timing (with dedup).
|
|
104
103
|
*/
|
|
105
|
-
#
|
|
104
|
+
#perfTracker;
|
|
106
105
|
/**
|
|
107
|
-
*
|
|
106
|
+
* Performance tracker shared by all guests (no dedup).
|
|
108
107
|
*/
|
|
109
|
-
#
|
|
110
|
-
static DEFAULT_TIMING_DEDUP_WINDOW_MS = 1e4;
|
|
108
|
+
#guestPerfTracker;
|
|
111
109
|
/**
|
|
112
110
|
* Create a new host
|
|
113
111
|
* @param hostId unique identifier for the host
|
|
@@ -119,7 +117,20 @@ class SSFHost {
|
|
|
119
117
|
if (!option?.analyticsObj) throw new Error("Analytics object is required");
|
|
120
118
|
this.#logger = option.logger;
|
|
121
119
|
this.#analyticsObj = option.analyticsObj;
|
|
122
|
-
|
|
120
|
+
const perfOpts = {
|
|
121
|
+
analyticsObj: option.analyticsObj,
|
|
122
|
+
enabled: option?.measurePerformance,
|
|
123
|
+
samplingRatio: option?.performanceSamplingRatio,
|
|
124
|
+
onError: (msg) => this.#logger.debug(msg)
|
|
125
|
+
};
|
|
126
|
+
this.#perfTracker = new import_performanceTracker.PerformanceTracker({
|
|
127
|
+
...perfOpts,
|
|
128
|
+
dedupWindowMs: option?.performanceDedupWindowMs
|
|
129
|
+
});
|
|
130
|
+
this.#guestPerfTracker = new import_performanceTracker.PerformanceTracker({
|
|
131
|
+
...perfOpts,
|
|
132
|
+
dedupWindowMs: 0
|
|
133
|
+
});
|
|
123
134
|
this.#correlationId = (0, import_uuid.v4)();
|
|
124
135
|
this.#remoting = new import_microfe_common.Remoting(this.#logger, this.#correlationId);
|
|
125
136
|
if (option?.readyStateCallback && typeof option?.readyStateCallback !== "function")
|
|
@@ -143,34 +154,6 @@ class SSFHost {
|
|
|
143
154
|
);
|
|
144
155
|
});
|
|
145
156
|
};
|
|
146
|
-
#startTiming = (name, options) => {
|
|
147
|
-
this.#analyticsObj.startTiming(name, options).catch((e) => {
|
|
148
|
-
this.#logger.debug(
|
|
149
|
-
`Analytics startTiming failed: ${e.message}`
|
|
150
|
-
);
|
|
151
|
-
});
|
|
152
|
-
};
|
|
153
|
-
#endTiming = (start, options) => {
|
|
154
|
-
this.#analyticsObj.endTiming(start, options).catch((e) => {
|
|
155
|
-
this.#logger.debug(`Analytics endTiming failed: ${e.message}`);
|
|
156
|
-
});
|
|
157
|
-
};
|
|
158
|
-
/**
|
|
159
|
-
* Returns true if a timing measurement should be recorded for the given
|
|
160
|
-
* metric name. Skips the measurement when one was already recorded for the
|
|
161
|
-
* same name within the configured dedup window ({@link HostOption.timingDedupWindowMs}).
|
|
162
|
-
* Always returns true when dedup is disabled (window = 0).
|
|
163
|
-
* @param name
|
|
164
|
-
*/
|
|
165
|
-
#shouldTrackTiming = (name) => {
|
|
166
|
-
if (this.#timingDedupWindowMs <= 0) return true;
|
|
167
|
-
const now = performance.now();
|
|
168
|
-
const last = this.#timingLastRecorded.get(name);
|
|
169
|
-
if (last !== void 0 && now - last < this.#timingDedupWindowMs)
|
|
170
|
-
return false;
|
|
171
|
-
this.#timingLastRecorded.set(name, now);
|
|
172
|
-
return true;
|
|
173
|
-
};
|
|
174
157
|
#closeAllPopupGuests = () => {
|
|
175
158
|
const popupIds = Array.from(this.#guests.values()).filter((guest) => guest.openMode === import_types.OpenMode.Popup).map((guest) => guest.id);
|
|
176
159
|
popupIds.forEach((id) => this.unloadGuest(id));
|
|
@@ -293,7 +276,7 @@ class SSFHost {
|
|
|
293
276
|
if (!guest.ready) {
|
|
294
277
|
guest.ready = true;
|
|
295
278
|
const guestInfo = guest.getInfo();
|
|
296
|
-
this.#
|
|
279
|
+
this.#perfTracker.end("SSF.Guest.Load", {
|
|
297
280
|
appId: guestInfo.guestId,
|
|
298
281
|
appUrl: guestInfo.guestUrl
|
|
299
282
|
});
|
|
@@ -566,10 +549,10 @@ class SSFHost {
|
|
|
566
549
|
return false;
|
|
567
550
|
}
|
|
568
551
|
const guestInfo = guest.getInfo();
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
this.#
|
|
552
|
+
let timingToken;
|
|
553
|
+
if (this.#perfTracker.enabled) {
|
|
554
|
+
const name = `ScriptingObject.API.${objectId}.${body.functionName}`;
|
|
555
|
+
timingToken = this.#perfTracker.start(name, {
|
|
573
556
|
appId: guestInfo.guestId,
|
|
574
557
|
appUrl: guestInfo.guestUrl
|
|
575
558
|
});
|
|
@@ -609,8 +592,8 @@ class SSFHost {
|
|
|
609
592
|
...guestInfo
|
|
610
593
|
});
|
|
611
594
|
}).finally(() => {
|
|
612
|
-
if (
|
|
613
|
-
this.#
|
|
595
|
+
if (timingToken) {
|
|
596
|
+
this.#perfTracker.end(timingToken, {
|
|
614
597
|
appId: guestInfo.guestId,
|
|
615
598
|
appUrl: guestInfo.guestUrl
|
|
616
599
|
});
|
|
@@ -685,7 +668,7 @@ class SSFHost {
|
|
|
685
668
|
const guest = new import_guest.Guest({
|
|
686
669
|
...param,
|
|
687
670
|
remoting: this.#remoting,
|
|
688
|
-
|
|
671
|
+
perfTracker: this.#guestPerfTracker
|
|
689
672
|
});
|
|
690
673
|
guest.init();
|
|
691
674
|
this.#guests.set(param.guestId, guest);
|
|
@@ -1058,18 +1041,16 @@ class SSFHost {
|
|
|
1058
1041
|
};
|
|
1059
1042
|
}
|
|
1060
1043
|
const guestPromises = [];
|
|
1061
|
-
|
|
1062
|
-
let timingMetricStarted = false;
|
|
1044
|
+
let eventTimingToken;
|
|
1063
1045
|
const dispatchToGuest = (guest) => {
|
|
1064
1046
|
const guestInfo = guest.getInfo();
|
|
1065
1047
|
if (timeout && guest?.capabilities?.eventFeedback) {
|
|
1066
1048
|
guestPromises.push(guest.dispatchEvent(eventObj, timeout));
|
|
1067
|
-
if (!
|
|
1068
|
-
this.#
|
|
1069
|
-
|
|
1070
|
-
appUrl: window.location.href
|
|
1071
|
-
|
|
1072
|
-
timingMetricStarted = true;
|
|
1049
|
+
if (!eventTimingToken && this.#perfTracker.enabled) {
|
|
1050
|
+
eventTimingToken = this.#perfTracker.start(
|
|
1051
|
+
`ScriptingObject.Event.${scriptingObject.id}.${name}`,
|
|
1052
|
+
{ appId: this.hostId, appUrl: window.location.href }
|
|
1053
|
+
);
|
|
1073
1054
|
}
|
|
1074
1055
|
this.#logger.debug({
|
|
1075
1056
|
message: "Event dispatched and awaiting feedback",
|
|
@@ -1107,11 +1088,12 @@ class SSFHost {
|
|
|
1107
1088
|
});
|
|
1108
1089
|
throw ex;
|
|
1109
1090
|
}).finally(() => {
|
|
1110
|
-
if (
|
|
1111
|
-
this.#
|
|
1091
|
+
if (eventTimingToken) {
|
|
1092
|
+
this.#perfTracker.end(eventTimingToken, {
|
|
1112
1093
|
appId: this.hostId,
|
|
1113
1094
|
appUrl: window.location.href
|
|
1114
1095
|
});
|
|
1096
|
+
}
|
|
1115
1097
|
});
|
|
1116
1098
|
};
|
|
1117
1099
|
/**
|
|
@@ -1155,7 +1137,7 @@ class SSFHost {
|
|
|
1155
1137
|
const { openMode = import_types.OpenMode.Embed, popupWindowFeatures = {} } = options;
|
|
1156
1138
|
const srcUrl = this.#getGuestUrl(url, searchParams);
|
|
1157
1139
|
let guest = null;
|
|
1158
|
-
this.#
|
|
1140
|
+
this.#perfTracker.start("SSF.Guest.Load", {
|
|
1159
1141
|
appId: instanceId,
|
|
1160
1142
|
appUrl: srcUrl
|
|
1161
1143
|
});
|
|
@@ -0,0 +1,111 @@
|
|
|
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 performanceTracker_exports = {};
|
|
20
|
+
__export(performanceTracker_exports, {
|
|
21
|
+
PerformanceTracker: () => PerformanceTracker
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(performanceTracker_exports);
|
|
24
|
+
class PerformanceTracker {
|
|
25
|
+
#analyticsObj;
|
|
26
|
+
#enabled;
|
|
27
|
+
#samplingRatio;
|
|
28
|
+
#samplingConfigured = /* @__PURE__ */ new Set();
|
|
29
|
+
#dedupWindowMs;
|
|
30
|
+
#lastRecorded = /* @__PURE__ */ new Map();
|
|
31
|
+
#onError;
|
|
32
|
+
static DEFAULT_SAMPLING_RATIO = 0.05;
|
|
33
|
+
static DEFAULT_DEDUP_WINDOW_MS = 1e4;
|
|
34
|
+
static #LOW_FREQUENCY = /* @__PURE__ */ new Set(["SSF.Guest.Load"]);
|
|
35
|
+
constructor(options) {
|
|
36
|
+
this.#analyticsObj = options.analyticsObj;
|
|
37
|
+
this.#enabled = options.enabled ?? false;
|
|
38
|
+
this.#samplingRatio = options.samplingRatio ?? PerformanceTracker.DEFAULT_SAMPLING_RATIO;
|
|
39
|
+
this.#dedupWindowMs = options.dedupWindowMs ?? PerformanceTracker.DEFAULT_DEDUP_WINDOW_MS;
|
|
40
|
+
this.#onError = options.onError;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Whether performance tracking is active. Callers can use this to
|
|
44
|
+
* skip expensive work (e.g. building timing name strings) when
|
|
45
|
+
* tracking is disabled.
|
|
46
|
+
* @returns {boolean} true when performance tracking is enabled
|
|
47
|
+
*/
|
|
48
|
+
get enabled() {
|
|
49
|
+
return this.#enabled;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Begin a timing measurement. Returns the timing name as a token when
|
|
53
|
+
* timing was started, or `undefined` when timing is disabled, deduped,
|
|
54
|
+
* or skipped. Pass the returned token to {@link end}.
|
|
55
|
+
* Never throws — failures are reported via the `onError` callback.
|
|
56
|
+
* @param {string} name - timing event name
|
|
57
|
+
* @param {TimingOptions} options - context passed to the analytics object
|
|
58
|
+
* @returns {string | undefined} the timing token, or undefined if skipped
|
|
59
|
+
*/
|
|
60
|
+
start(name, options) {
|
|
61
|
+
if (!this.#enabled) return void 0;
|
|
62
|
+
try {
|
|
63
|
+
const lowFreq = PerformanceTracker.#LOW_FREQUENCY.has(name);
|
|
64
|
+
if (!lowFreq && !this.#shouldTrack(name)) return void 0;
|
|
65
|
+
if (!lowFreq && !this.#samplingConfigured.has(name)) {
|
|
66
|
+
this.#analyticsObj.setTimingEventSamplingRatio({
|
|
67
|
+
[name]: this.#samplingRatio
|
|
68
|
+
});
|
|
69
|
+
this.#samplingConfigured.add(name);
|
|
70
|
+
}
|
|
71
|
+
this.#analyticsObj.startTiming(name, options).catch((e) => {
|
|
72
|
+
this.#reportError(`startTiming failed: ${e.message}`);
|
|
73
|
+
});
|
|
74
|
+
return name;
|
|
75
|
+
} catch (e) {
|
|
76
|
+
this.#reportError(`startTiming failed: ${e.message}`);
|
|
77
|
+
return void 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* End a timing measurement previously started via {@link start}.
|
|
82
|
+
* No-op when token is `undefined` (timing was not started).
|
|
83
|
+
* Never throws — failures are reported via the `onError` callback.
|
|
84
|
+
* @param {string | undefined} token - token returned by {@link start}
|
|
85
|
+
* @param {TimingOptions} options - context passed to the analytics object
|
|
86
|
+
*/
|
|
87
|
+
end(token, options) {
|
|
88
|
+
if (!token) return;
|
|
89
|
+
try {
|
|
90
|
+
this.#analyticsObj.endTiming(token, options).catch((e) => {
|
|
91
|
+
this.#reportError(`endTiming failed: ${e.message}`);
|
|
92
|
+
});
|
|
93
|
+
} catch (e) {
|
|
94
|
+
this.#reportError(`endTiming failed: ${e.message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
#reportError(message) {
|
|
98
|
+
try {
|
|
99
|
+
this.#onError?.(message);
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
#shouldTrack(name) {
|
|
104
|
+
if (this.#dedupWindowMs <= 0) return true;
|
|
105
|
+
const now = performance.now();
|
|
106
|
+
const last = this.#lastRecorded.get(name);
|
|
107
|
+
if (last !== void 0 && now - last < this.#dedupWindowMs) return false;
|
|
108
|
+
this.#lastRecorded.set(name, now);
|
|
109
|
+
return true;
|
|
110
|
+
}
|
|
111
|
+
}
|
package/dist/esm/guest.js
CHANGED
|
@@ -51,9 +51,9 @@ class Guest {
|
|
|
51
51
|
*/
|
|
52
52
|
#remoting;
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* performance tracker for timing measurements
|
|
55
55
|
*/
|
|
56
|
-
#
|
|
56
|
+
#perfTracker;
|
|
57
57
|
/**
|
|
58
58
|
* Create object representing guest application
|
|
59
59
|
* @param {GuestOption} option - options for creating a guest application
|
|
@@ -68,7 +68,7 @@ class Guest {
|
|
|
68
68
|
searchParams = {},
|
|
69
69
|
openMode = OpenMode.Embed,
|
|
70
70
|
remoting,
|
|
71
|
-
|
|
71
|
+
perfTracker
|
|
72
72
|
} = option;
|
|
73
73
|
this.id = guestId;
|
|
74
74
|
this.title = title;
|
|
@@ -79,7 +79,7 @@ class Guest {
|
|
|
79
79
|
this.window = window;
|
|
80
80
|
this.openMode = openMode;
|
|
81
81
|
this.capabilities = {};
|
|
82
|
-
this.#
|
|
82
|
+
this.#perfTracker = perfTracker;
|
|
83
83
|
this.#remoting = remoting;
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
@@ -165,16 +165,17 @@ class Guest {
|
|
|
165
165
|
* invokes event callback on the guest application
|
|
166
166
|
* @param {EventObject} event - event object
|
|
167
167
|
* @param {number} timeout - timeout in milliseconds
|
|
168
|
+
* @returns {Promise} resolves when the guest handles the event
|
|
168
169
|
*/
|
|
169
170
|
dispatchEvent = (event, timeout) => {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
{
|
|
171
|
+
let timingToken;
|
|
172
|
+
if (this.#perfTracker.enabled) {
|
|
173
|
+
const name = `ScriptingObject.Event.${event.object.objectId}.${event.eventName}`;
|
|
174
|
+
timingToken = this.#perfTracker.start(name, {
|
|
173
175
|
appId: this.id,
|
|
174
176
|
appUrl: this.url
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
});
|
|
177
|
+
});
|
|
178
|
+
}
|
|
178
179
|
return this.#remoting.invoke({
|
|
179
180
|
targetWin: this.window,
|
|
180
181
|
targetOrigin: this.origin,
|
|
@@ -182,14 +183,12 @@ class Guest {
|
|
|
182
183
|
messageBody: event,
|
|
183
184
|
responseTimeoutMs: timeout
|
|
184
185
|
}).finally(() => {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
{
|
|
186
|
+
if (timingToken) {
|
|
187
|
+
this.#perfTracker.end(timingToken, {
|
|
188
188
|
appId: this.id,
|
|
189
189
|
appUrl: this.url
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
});
|
|
190
|
+
});
|
|
191
|
+
}
|
|
193
192
|
});
|
|
194
193
|
};
|
|
195
194
|
/**
|
package/dist/esm/host.js
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "./types.js";
|
|
15
15
|
import { Guest } from "./guest.js";
|
|
16
16
|
import { flatten, isFunction, isTrustedDomain } from "./utils.js";
|
|
17
|
+
import { PerformanceTracker } from "./performanceTracker.js";
|
|
17
18
|
const SANDBOX_DEFAULT = [
|
|
18
19
|
IFrameSandboxValues.AllowScripts,
|
|
19
20
|
IFrameSandboxValues.AllowPopups,
|
|
@@ -85,16 +86,13 @@ class SSFHost {
|
|
|
85
86
|
*/
|
|
86
87
|
#guestMetadata = /* @__PURE__ */ new Map();
|
|
87
88
|
/**
|
|
88
|
-
*
|
|
89
|
-
* Used to skip redundant startTiming/endTiming cross-window calls for
|
|
90
|
-
* the same API or event within the dedup window.
|
|
89
|
+
* Performance tracker for host-side timing (with dedup).
|
|
91
90
|
*/
|
|
92
|
-
#
|
|
91
|
+
#perfTracker;
|
|
93
92
|
/**
|
|
94
|
-
*
|
|
93
|
+
* Performance tracker shared by all guests (no dedup).
|
|
95
94
|
*/
|
|
96
|
-
#
|
|
97
|
-
static DEFAULT_TIMING_DEDUP_WINDOW_MS = 1e4;
|
|
95
|
+
#guestPerfTracker;
|
|
98
96
|
/**
|
|
99
97
|
* Create a new host
|
|
100
98
|
* @param hostId unique identifier for the host
|
|
@@ -106,7 +104,20 @@ class SSFHost {
|
|
|
106
104
|
if (!option?.analyticsObj) throw new Error("Analytics object is required");
|
|
107
105
|
this.#logger = option.logger;
|
|
108
106
|
this.#analyticsObj = option.analyticsObj;
|
|
109
|
-
|
|
107
|
+
const perfOpts = {
|
|
108
|
+
analyticsObj: option.analyticsObj,
|
|
109
|
+
enabled: option?.measurePerformance,
|
|
110
|
+
samplingRatio: option?.performanceSamplingRatio,
|
|
111
|
+
onError: (msg) => this.#logger.debug(msg)
|
|
112
|
+
};
|
|
113
|
+
this.#perfTracker = new PerformanceTracker({
|
|
114
|
+
...perfOpts,
|
|
115
|
+
dedupWindowMs: option?.performanceDedupWindowMs
|
|
116
|
+
});
|
|
117
|
+
this.#guestPerfTracker = new PerformanceTracker({
|
|
118
|
+
...perfOpts,
|
|
119
|
+
dedupWindowMs: 0
|
|
120
|
+
});
|
|
110
121
|
this.#correlationId = uuidv4();
|
|
111
122
|
this.#remoting = new Remoting(this.#logger, this.#correlationId);
|
|
112
123
|
if (option?.readyStateCallback && typeof option?.readyStateCallback !== "function")
|
|
@@ -130,34 +141,6 @@ class SSFHost {
|
|
|
130
141
|
);
|
|
131
142
|
});
|
|
132
143
|
};
|
|
133
|
-
#startTiming = (name, options) => {
|
|
134
|
-
this.#analyticsObj.startTiming(name, options).catch((e) => {
|
|
135
|
-
this.#logger.debug(
|
|
136
|
-
`Analytics startTiming failed: ${e.message}`
|
|
137
|
-
);
|
|
138
|
-
});
|
|
139
|
-
};
|
|
140
|
-
#endTiming = (start, options) => {
|
|
141
|
-
this.#analyticsObj.endTiming(start, options).catch((e) => {
|
|
142
|
-
this.#logger.debug(`Analytics endTiming failed: ${e.message}`);
|
|
143
|
-
});
|
|
144
|
-
};
|
|
145
|
-
/**
|
|
146
|
-
* Returns true if a timing measurement should be recorded for the given
|
|
147
|
-
* metric name. Skips the measurement when one was already recorded for the
|
|
148
|
-
* same name within the configured dedup window ({@link HostOption.timingDedupWindowMs}).
|
|
149
|
-
* Always returns true when dedup is disabled (window = 0).
|
|
150
|
-
* @param name
|
|
151
|
-
*/
|
|
152
|
-
#shouldTrackTiming = (name) => {
|
|
153
|
-
if (this.#timingDedupWindowMs <= 0) return true;
|
|
154
|
-
const now = performance.now();
|
|
155
|
-
const last = this.#timingLastRecorded.get(name);
|
|
156
|
-
if (last !== void 0 && now - last < this.#timingDedupWindowMs)
|
|
157
|
-
return false;
|
|
158
|
-
this.#timingLastRecorded.set(name, now);
|
|
159
|
-
return true;
|
|
160
|
-
};
|
|
161
144
|
#closeAllPopupGuests = () => {
|
|
162
145
|
const popupIds = Array.from(this.#guests.values()).filter((guest) => guest.openMode === OpenMode.Popup).map((guest) => guest.id);
|
|
163
146
|
popupIds.forEach((id) => this.unloadGuest(id));
|
|
@@ -280,7 +263,7 @@ class SSFHost {
|
|
|
280
263
|
if (!guest.ready) {
|
|
281
264
|
guest.ready = true;
|
|
282
265
|
const guestInfo = guest.getInfo();
|
|
283
|
-
this.#
|
|
266
|
+
this.#perfTracker.end("SSF.Guest.Load", {
|
|
284
267
|
appId: guestInfo.guestId,
|
|
285
268
|
appUrl: guestInfo.guestUrl
|
|
286
269
|
});
|
|
@@ -553,10 +536,10 @@ class SSFHost {
|
|
|
553
536
|
return false;
|
|
554
537
|
}
|
|
555
538
|
const guestInfo = guest.getInfo();
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
this.#
|
|
539
|
+
let timingToken;
|
|
540
|
+
if (this.#perfTracker.enabled) {
|
|
541
|
+
const name = `ScriptingObject.API.${objectId}.${body.functionName}`;
|
|
542
|
+
timingToken = this.#perfTracker.start(name, {
|
|
560
543
|
appId: guestInfo.guestId,
|
|
561
544
|
appUrl: guestInfo.guestUrl
|
|
562
545
|
});
|
|
@@ -596,8 +579,8 @@ class SSFHost {
|
|
|
596
579
|
...guestInfo
|
|
597
580
|
});
|
|
598
581
|
}).finally(() => {
|
|
599
|
-
if (
|
|
600
|
-
this.#
|
|
582
|
+
if (timingToken) {
|
|
583
|
+
this.#perfTracker.end(timingToken, {
|
|
601
584
|
appId: guestInfo.guestId,
|
|
602
585
|
appUrl: guestInfo.guestUrl
|
|
603
586
|
});
|
|
@@ -672,7 +655,7 @@ class SSFHost {
|
|
|
672
655
|
const guest = new Guest({
|
|
673
656
|
...param,
|
|
674
657
|
remoting: this.#remoting,
|
|
675
|
-
|
|
658
|
+
perfTracker: this.#guestPerfTracker
|
|
676
659
|
});
|
|
677
660
|
guest.init();
|
|
678
661
|
this.#guests.set(param.guestId, guest);
|
|
@@ -1045,18 +1028,16 @@ class SSFHost {
|
|
|
1045
1028
|
};
|
|
1046
1029
|
}
|
|
1047
1030
|
const guestPromises = [];
|
|
1048
|
-
|
|
1049
|
-
let timingMetricStarted = false;
|
|
1031
|
+
let eventTimingToken;
|
|
1050
1032
|
const dispatchToGuest = (guest) => {
|
|
1051
1033
|
const guestInfo = guest.getInfo();
|
|
1052
1034
|
if (timeout && guest?.capabilities?.eventFeedback) {
|
|
1053
1035
|
guestPromises.push(guest.dispatchEvent(eventObj, timeout));
|
|
1054
|
-
if (!
|
|
1055
|
-
this.#
|
|
1056
|
-
|
|
1057
|
-
appUrl: window.location.href
|
|
1058
|
-
|
|
1059
|
-
timingMetricStarted = true;
|
|
1036
|
+
if (!eventTimingToken && this.#perfTracker.enabled) {
|
|
1037
|
+
eventTimingToken = this.#perfTracker.start(
|
|
1038
|
+
`ScriptingObject.Event.${scriptingObject.id}.${name}`,
|
|
1039
|
+
{ appId: this.hostId, appUrl: window.location.href }
|
|
1040
|
+
);
|
|
1060
1041
|
}
|
|
1061
1042
|
this.#logger.debug({
|
|
1062
1043
|
message: "Event dispatched and awaiting feedback",
|
|
@@ -1094,11 +1075,12 @@ class SSFHost {
|
|
|
1094
1075
|
});
|
|
1095
1076
|
throw ex;
|
|
1096
1077
|
}).finally(() => {
|
|
1097
|
-
if (
|
|
1098
|
-
this.#
|
|
1078
|
+
if (eventTimingToken) {
|
|
1079
|
+
this.#perfTracker.end(eventTimingToken, {
|
|
1099
1080
|
appId: this.hostId,
|
|
1100
1081
|
appUrl: window.location.href
|
|
1101
1082
|
});
|
|
1083
|
+
}
|
|
1102
1084
|
});
|
|
1103
1085
|
};
|
|
1104
1086
|
/**
|
|
@@ -1142,7 +1124,7 @@ class SSFHost {
|
|
|
1142
1124
|
const { openMode = OpenMode.Embed, popupWindowFeatures = {} } = options;
|
|
1143
1125
|
const srcUrl = this.#getGuestUrl(url, searchParams);
|
|
1144
1126
|
let guest = null;
|
|
1145
|
-
this.#
|
|
1127
|
+
this.#perfTracker.start("SSF.Guest.Load", {
|
|
1146
1128
|
appId: instanceId,
|
|
1147
1129
|
appUrl: srcUrl
|
|
1148
1130
|
});
|