@elliemae/ssf-host 2.24.0 → 2.25.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/dist/cjs/guest.js +15 -16
- package/dist/cjs/host.js +40 -56
- package/dist/cjs/performanceTracker.js +111 -0
- package/dist/esm/guest.js +15 -16
- package/dist/esm/host.js +40 -56
- 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.7dbe9d9cafa1bad23e6c.js +3 -0
- package/dist/public/js/emuiSsfHost.7dbe9d9cafa1bad23e6c.js.br +0 -0
- package/dist/public/js/emuiSsfHost.7dbe9d9cafa1bad23e6c.js.gz +0 -0
- package/dist/public/js/emuiSsfHost.7dbe9d9cafa1bad23e6c.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 +26 -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,9 +117,24 @@ 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
|
-
this.#remoting = new import_microfe_common.Remoting(this.#logger, this.#correlationId
|
|
135
|
+
this.#remoting = new import_microfe_common.Remoting(this.#logger, this.#correlationId, {
|
|
136
|
+
unsafeAllowAnyGuestOrigin: option?.unsafeAllowAnyGuestOrigin
|
|
137
|
+
});
|
|
125
138
|
if (option?.readyStateCallback && typeof option?.readyStateCallback !== "function")
|
|
126
139
|
throw new Error("readyStateCallback must be a function");
|
|
127
140
|
this.#readyStateCallback = option?.readyStateCallback || null;
|
|
@@ -143,34 +156,6 @@ class SSFHost {
|
|
|
143
156
|
);
|
|
144
157
|
});
|
|
145
158
|
};
|
|
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
159
|
#closeAllPopupGuests = () => {
|
|
175
160
|
const popupIds = Array.from(this.#guests.values()).filter((guest) => guest.openMode === import_types.OpenMode.Popup).map((guest) => guest.id);
|
|
176
161
|
popupIds.forEach((id) => this.unloadGuest(id));
|
|
@@ -293,7 +278,7 @@ class SSFHost {
|
|
|
293
278
|
if (!guest.ready) {
|
|
294
279
|
guest.ready = true;
|
|
295
280
|
const guestInfo = guest.getInfo();
|
|
296
|
-
this.#
|
|
281
|
+
this.#perfTracker.end("SSF.Guest.Load", {
|
|
297
282
|
appId: guestInfo.guestId,
|
|
298
283
|
appUrl: guestInfo.guestUrl
|
|
299
284
|
});
|
|
@@ -566,10 +551,10 @@ class SSFHost {
|
|
|
566
551
|
return false;
|
|
567
552
|
}
|
|
568
553
|
const guestInfo = guest.getInfo();
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
this.#
|
|
554
|
+
let timingToken;
|
|
555
|
+
if (this.#perfTracker.enabled) {
|
|
556
|
+
const name = `ScriptingObject.API.${objectId}.${body.functionName}`;
|
|
557
|
+
timingToken = this.#perfTracker.start(name, {
|
|
573
558
|
appId: guestInfo.guestId,
|
|
574
559
|
appUrl: guestInfo.guestUrl
|
|
575
560
|
});
|
|
@@ -609,8 +594,8 @@ class SSFHost {
|
|
|
609
594
|
...guestInfo
|
|
610
595
|
});
|
|
611
596
|
}).finally(() => {
|
|
612
|
-
if (
|
|
613
|
-
this.#
|
|
597
|
+
if (timingToken) {
|
|
598
|
+
this.#perfTracker.end(timingToken, {
|
|
614
599
|
appId: guestInfo.guestId,
|
|
615
600
|
appUrl: guestInfo.guestUrl
|
|
616
601
|
});
|
|
@@ -685,7 +670,7 @@ class SSFHost {
|
|
|
685
670
|
const guest = new import_guest.Guest({
|
|
686
671
|
...param,
|
|
687
672
|
remoting: this.#remoting,
|
|
688
|
-
|
|
673
|
+
perfTracker: this.#guestPerfTracker
|
|
689
674
|
});
|
|
690
675
|
guest.init();
|
|
691
676
|
this.#guests.set(param.guestId, guest);
|
|
@@ -1058,18 +1043,16 @@ class SSFHost {
|
|
|
1058
1043
|
};
|
|
1059
1044
|
}
|
|
1060
1045
|
const guestPromises = [];
|
|
1061
|
-
|
|
1062
|
-
let timingMetricStarted = false;
|
|
1046
|
+
let eventTimingToken;
|
|
1063
1047
|
const dispatchToGuest = (guest) => {
|
|
1064
1048
|
const guestInfo = guest.getInfo();
|
|
1065
1049
|
if (timeout && guest?.capabilities?.eventFeedback) {
|
|
1066
1050
|
guestPromises.push(guest.dispatchEvent(eventObj, timeout));
|
|
1067
|
-
if (!
|
|
1068
|
-
this.#
|
|
1069
|
-
|
|
1070
|
-
appUrl: window.location.href
|
|
1071
|
-
|
|
1072
|
-
timingMetricStarted = true;
|
|
1051
|
+
if (!eventTimingToken && this.#perfTracker.enabled) {
|
|
1052
|
+
eventTimingToken = this.#perfTracker.start(
|
|
1053
|
+
`ScriptingObject.Event.${scriptingObject.id}.${name}`,
|
|
1054
|
+
{ appId: this.hostId, appUrl: window.location.href }
|
|
1055
|
+
);
|
|
1073
1056
|
}
|
|
1074
1057
|
this.#logger.debug({
|
|
1075
1058
|
message: "Event dispatched and awaiting feedback",
|
|
@@ -1107,11 +1090,12 @@ class SSFHost {
|
|
|
1107
1090
|
});
|
|
1108
1091
|
throw ex;
|
|
1109
1092
|
}).finally(() => {
|
|
1110
|
-
if (
|
|
1111
|
-
this.#
|
|
1093
|
+
if (eventTimingToken) {
|
|
1094
|
+
this.#perfTracker.end(eventTimingToken, {
|
|
1112
1095
|
appId: this.hostId,
|
|
1113
1096
|
appUrl: window.location.href
|
|
1114
1097
|
});
|
|
1098
|
+
}
|
|
1115
1099
|
});
|
|
1116
1100
|
};
|
|
1117
1101
|
/**
|
|
@@ -1155,7 +1139,7 @@ class SSFHost {
|
|
|
1155
1139
|
const { openMode = import_types.OpenMode.Embed, popupWindowFeatures = {} } = options;
|
|
1156
1140
|
const srcUrl = this.#getGuestUrl(url, searchParams);
|
|
1157
1141
|
let guest = null;
|
|
1158
|
-
this.#
|
|
1142
|
+
this.#perfTracker.start("SSF.Guest.Load", {
|
|
1159
1143
|
appId: instanceId,
|
|
1160
1144
|
appUrl: srcUrl
|
|
1161
1145
|
});
|
|
@@ -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,9 +104,24 @@ 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
|
-
this.#remoting = new Remoting(this.#logger, this.#correlationId
|
|
122
|
+
this.#remoting = new Remoting(this.#logger, this.#correlationId, {
|
|
123
|
+
unsafeAllowAnyGuestOrigin: option?.unsafeAllowAnyGuestOrigin
|
|
124
|
+
});
|
|
112
125
|
if (option?.readyStateCallback && typeof option?.readyStateCallback !== "function")
|
|
113
126
|
throw new Error("readyStateCallback must be a function");
|
|
114
127
|
this.#readyStateCallback = option?.readyStateCallback || null;
|
|
@@ -130,34 +143,6 @@ class SSFHost {
|
|
|
130
143
|
);
|
|
131
144
|
});
|
|
132
145
|
};
|
|
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
146
|
#closeAllPopupGuests = () => {
|
|
162
147
|
const popupIds = Array.from(this.#guests.values()).filter((guest) => guest.openMode === OpenMode.Popup).map((guest) => guest.id);
|
|
163
148
|
popupIds.forEach((id) => this.unloadGuest(id));
|
|
@@ -280,7 +265,7 @@ class SSFHost {
|
|
|
280
265
|
if (!guest.ready) {
|
|
281
266
|
guest.ready = true;
|
|
282
267
|
const guestInfo = guest.getInfo();
|
|
283
|
-
this.#
|
|
268
|
+
this.#perfTracker.end("SSF.Guest.Load", {
|
|
284
269
|
appId: guestInfo.guestId,
|
|
285
270
|
appUrl: guestInfo.guestUrl
|
|
286
271
|
});
|
|
@@ -553,10 +538,10 @@ class SSFHost {
|
|
|
553
538
|
return false;
|
|
554
539
|
}
|
|
555
540
|
const guestInfo = guest.getInfo();
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
this.#
|
|
541
|
+
let timingToken;
|
|
542
|
+
if (this.#perfTracker.enabled) {
|
|
543
|
+
const name = `ScriptingObject.API.${objectId}.${body.functionName}`;
|
|
544
|
+
timingToken = this.#perfTracker.start(name, {
|
|
560
545
|
appId: guestInfo.guestId,
|
|
561
546
|
appUrl: guestInfo.guestUrl
|
|
562
547
|
});
|
|
@@ -596,8 +581,8 @@ class SSFHost {
|
|
|
596
581
|
...guestInfo
|
|
597
582
|
});
|
|
598
583
|
}).finally(() => {
|
|
599
|
-
if (
|
|
600
|
-
this.#
|
|
584
|
+
if (timingToken) {
|
|
585
|
+
this.#perfTracker.end(timingToken, {
|
|
601
586
|
appId: guestInfo.guestId,
|
|
602
587
|
appUrl: guestInfo.guestUrl
|
|
603
588
|
});
|
|
@@ -672,7 +657,7 @@ class SSFHost {
|
|
|
672
657
|
const guest = new Guest({
|
|
673
658
|
...param,
|
|
674
659
|
remoting: this.#remoting,
|
|
675
|
-
|
|
660
|
+
perfTracker: this.#guestPerfTracker
|
|
676
661
|
});
|
|
677
662
|
guest.init();
|
|
678
663
|
this.#guests.set(param.guestId, guest);
|
|
@@ -1045,18 +1030,16 @@ class SSFHost {
|
|
|
1045
1030
|
};
|
|
1046
1031
|
}
|
|
1047
1032
|
const guestPromises = [];
|
|
1048
|
-
|
|
1049
|
-
let timingMetricStarted = false;
|
|
1033
|
+
let eventTimingToken;
|
|
1050
1034
|
const dispatchToGuest = (guest) => {
|
|
1051
1035
|
const guestInfo = guest.getInfo();
|
|
1052
1036
|
if (timeout && guest?.capabilities?.eventFeedback) {
|
|
1053
1037
|
guestPromises.push(guest.dispatchEvent(eventObj, timeout));
|
|
1054
|
-
if (!
|
|
1055
|
-
this.#
|
|
1056
|
-
|
|
1057
|
-
appUrl: window.location.href
|
|
1058
|
-
|
|
1059
|
-
timingMetricStarted = true;
|
|
1038
|
+
if (!eventTimingToken && this.#perfTracker.enabled) {
|
|
1039
|
+
eventTimingToken = this.#perfTracker.start(
|
|
1040
|
+
`ScriptingObject.Event.${scriptingObject.id}.${name}`,
|
|
1041
|
+
{ appId: this.hostId, appUrl: window.location.href }
|
|
1042
|
+
);
|
|
1060
1043
|
}
|
|
1061
1044
|
this.#logger.debug({
|
|
1062
1045
|
message: "Event dispatched and awaiting feedback",
|
|
@@ -1094,11 +1077,12 @@ class SSFHost {
|
|
|
1094
1077
|
});
|
|
1095
1078
|
throw ex;
|
|
1096
1079
|
}).finally(() => {
|
|
1097
|
-
if (
|
|
1098
|
-
this.#
|
|
1080
|
+
if (eventTimingToken) {
|
|
1081
|
+
this.#perfTracker.end(eventTimingToken, {
|
|
1099
1082
|
appId: this.hostId,
|
|
1100
1083
|
appUrl: window.location.href
|
|
1101
1084
|
});
|
|
1085
|
+
}
|
|
1102
1086
|
});
|
|
1103
1087
|
};
|
|
1104
1088
|
/**
|
|
@@ -1142,7 +1126,7 @@ class SSFHost {
|
|
|
1142
1126
|
const { openMode = OpenMode.Embed, popupWindowFeatures = {} } = options;
|
|
1143
1127
|
const srcUrl = this.#getGuestUrl(url, searchParams);
|
|
1144
1128
|
let guest = null;
|
|
1145
|
-
this.#
|
|
1129
|
+
this.#perfTracker.start("SSF.Guest.Load", {
|
|
1146
1130
|
appId: instanceId,
|
|
1147
1131
|
appUrl: srcUrl
|
|
1148
1132
|
});
|