@elliemae/ssf-host 2.23.6 → 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/callchain-host.html +262 -0
- package/dist/cjs/callchain-intermediate.html +92 -0
- package/dist/cjs/e2e-host.html +603 -0
- package/dist/cjs/e2e-index.html +234 -0
- package/dist/cjs/guest.js +15 -16
- package/dist/cjs/host.js +91 -52
- package/dist/cjs/index.html +304 -151
- package/dist/cjs/performanceTracker.js +111 -0
- package/dist/cjs/popup-focus-host.html +318 -0
- package/dist/cjs/utils.js +14 -1
- package/dist/cjs/v2-host-v1-guest.html +3 -0
- package/dist/esm/callchain-host.html +262 -0
- package/dist/esm/callchain-intermediate.html +92 -0
- package/dist/esm/e2e-host.html +603 -0
- package/dist/esm/e2e-index.html +234 -0
- package/dist/esm/guest.js +15 -16
- package/dist/esm/host.js +92 -53
- package/dist/esm/index.html +304 -151
- package/dist/esm/performanceTracker.js +91 -0
- package/dist/esm/popup-focus-host.html +318 -0
- package/dist/esm/utils.js +14 -1
- package/dist/esm/v2-host-v1-guest.html +3 -0
- package/dist/public/callchain-host.html +34 -0
- package/dist/public/callchain-host.js +3 -0
- package/dist/public/callchain-host.js.br +0 -0
- package/dist/public/callchain-host.js.gz +0 -0
- package/dist/public/callchain-host.js.map +1 -0
- package/dist/public/callchain-intermediate.html +1 -0
- package/dist/public/e2e-host.html +5 -0
- package/dist/public/e2e-host.js +8 -0
- package/dist/public/e2e-host.js.br +0 -0
- package/dist/public/e2e-host.js.gz +0 -0
- package/dist/public/e2e-host.js.map +1 -0
- package/dist/public/e2e-index.html +1 -0
- package/dist/public/index.html +1 -1
- package/dist/public/init.js +1 -1
- package/dist/public/init.js.br +0 -0
- package/dist/public/init.js.gz +0 -0
- package/dist/public/init.js.map +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/loan-object.js +1 -1
- package/dist/public/loan-object.js.br +0 -0
- package/dist/public/loan-object.js.gz +0 -0
- package/dist/public/loan-object.js.map +1 -1
- package/dist/public/popup-focus-host.html +1 -0
- package/dist/public/popup-focus-host.js +6 -0
- package/dist/public/popup-focus-host.js.br +0 -0
- package/dist/public/popup-focus-host.js.gz +0 -0
- package/dist/public/popup-focus-host.js.map +1 -0
- 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/ihost.d.ts +32 -0
- package/dist/types/lib/performanceTracker.d.ts +46 -0
- package/dist/types/lib/tests/timingDedup.test.d.ts +1 -0
- package/dist/types/lib/utils.d.ts +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dist/umd/callchain-host.html +34 -0
- package/dist/umd/callchain-host.js +3 -0
- package/dist/umd/callchain-host.js.br +0 -0
- package/dist/umd/callchain-host.js.gz +0 -0
- package/dist/umd/callchain-host.js.map +1 -0
- package/dist/umd/callchain-intermediate.html +1 -0
- package/dist/umd/e2e-host.html +5 -0
- package/dist/umd/e2e-host.js +8 -0
- package/dist/umd/e2e-host.js.br +0 -0
- package/dist/umd/e2e-host.js.gz +0 -0
- package/dist/umd/e2e-host.js.map +1 -0
- package/dist/umd/e2e-index.html +1 -0
- package/dist/umd/index.html +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/init.js +1 -1
- package/dist/umd/init.js.br +0 -0
- package/dist/umd/init.js.gz +0 -0
- package/dist/umd/init.js.map +1 -1
- package/dist/umd/loan-object.js +1 -1
- package/dist/umd/loan-object.js.br +0 -0
- package/dist/umd/loan-object.js.gz +0 -0
- package/dist/umd/loan-object.js.map +1 -1
- package/dist/umd/popup-focus-host.html +1 -0
- package/dist/umd/popup-focus-host.js +6 -0
- package/dist/umd/popup-focus-host.js.br +0 -0
- package/dist/umd/popup-focus-host.js.gz +0 -0
- package/dist/umd/popup-focus-host.js.map +1 -0
- 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/dist/umd/v2-host-v1-guest.html +1 -1
- package/package.json +6 -6
- package/dist/public/js/emuiSsfHost.5855ec3cd0fa60013d84.js +0 -3
- package/dist/public/js/emuiSsfHost.5855ec3cd0fa60013d84.js.br +0 -0
- package/dist/public/js/emuiSsfHost.5855ec3cd0fa60013d84.js.gz +0 -0
- package/dist/public/js/emuiSsfHost.5855ec3cd0fa60013d84.js.map +0 -1
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>SSF E2E Test Suite</title>
|
|
7
|
+
<script src="https://cdn.tailwindcss.com?plugins=forms"></script>
|
|
8
|
+
</head>
|
|
9
|
+
<body class="bg-gray-50">
|
|
10
|
+
<header class="bg-gray-900 text-white px-6 py-4">
|
|
11
|
+
<h1 class="text-xl font-bold">SSF End-to-End Test Suite</h1>
|
|
12
|
+
<p class="text-sm text-gray-400 mt-1">
|
|
13
|
+
Comprehensive blackbox tests for SSF Host & Guest. Each page
|
|
14
|
+
includes test steps, expected values, and a verification checklist.
|
|
15
|
+
</p>
|
|
16
|
+
</header>
|
|
17
|
+
|
|
18
|
+
<main class="mx-auto max-w-5xl px-6 py-6">
|
|
19
|
+
<!-- Setup -->
|
|
20
|
+
<section
|
|
21
|
+
class="mb-6 bg-yellow-50 border border-yellow-200 rounded-lg p-4"
|
|
22
|
+
>
|
|
23
|
+
<h2 class="text-sm font-semibold text-yellow-800 mb-2">
|
|
24
|
+
Setup Instructions
|
|
25
|
+
</h2>
|
|
26
|
+
<ol class="text-xs text-yellow-700 list-decimal ml-4 space-y-1">
|
|
27
|
+
<li>
|
|
28
|
+
Install dependencies:
|
|
29
|
+
<code class="bg-yellow-100 px-1 rounded">pnpm install</code>
|
|
30
|
+
</li>
|
|
31
|
+
<li>
|
|
32
|
+
Start SSF Host dev server:
|
|
33
|
+
<code class="bg-yellow-100 px-1 rounded"
|
|
34
|
+
>pnpm nx run ssf-host:start-server</code
|
|
35
|
+
>
|
|
36
|
+
(port 4000)
|
|
37
|
+
</li>
|
|
38
|
+
<li>
|
|
39
|
+
Start SSF Guest dev server:
|
|
40
|
+
<code class="bg-yellow-100 px-1 rounded"
|
|
41
|
+
>pnpm nx run ssf-guest:start</code
|
|
42
|
+
>
|
|
43
|
+
(port 4001)
|
|
44
|
+
</li>
|
|
45
|
+
<li>
|
|
46
|
+
Open
|
|
47
|
+
<code class="bg-yellow-100 px-1 rounded"
|
|
48
|
+
>http://localhost:4000/e2e-index.html</code
|
|
49
|
+
>
|
|
50
|
+
in the browser
|
|
51
|
+
</li>
|
|
52
|
+
<li>
|
|
53
|
+
Each test page has
|
|
54
|
+
<code class="bg-yellow-100 px-1 rounded">data-testid</code>
|
|
55
|
+
attributes for Playwright/Cypress selectors
|
|
56
|
+
</li>
|
|
57
|
+
</ol>
|
|
58
|
+
</section>
|
|
59
|
+
|
|
60
|
+
<!-- 1. Core Host-Guest Communication -->
|
|
61
|
+
<section class="mb-6">
|
|
62
|
+
<h2 class="text-lg font-semibold text-gray-800 border-b pb-1 mb-3">
|
|
63
|
+
1. Core Host-Guest Communication
|
|
64
|
+
</h2>
|
|
65
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
66
|
+
<a
|
|
67
|
+
href="./e2e-host.html"
|
|
68
|
+
data-testid="link-e2e-host"
|
|
69
|
+
class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
|
|
70
|
+
>
|
|
71
|
+
<h3 class="font-medium text-indigo-700">Comprehensive E2E Host</h3>
|
|
72
|
+
<p class="text-xs text-gray-500 mt-1">
|
|
73
|
+
All host-guest scenarios: guest loading, scripting objects,
|
|
74
|
+
events, lifecycle, metadata, sandbox, guest-scoped objects.
|
|
75
|
+
</p>
|
|
76
|
+
<p class="text-xs text-gray-400 mt-2">
|
|
77
|
+
<strong>What to verify:</strong> Guests load in iframes/popups.
|
|
78
|
+
Scripting objects can be added/removed/invoked. Events reach
|
|
79
|
+
subscribed guests. Unload/close cleans up properly. Sandbox attrs
|
|
80
|
+
applied.
|
|
81
|
+
</p>
|
|
82
|
+
<div class="mt-2 text-xs text-gray-400">
|
|
83
|
+
<strong>Test Cases:</strong>
|
|
84
|
+
TC-LOAD-01..05 • TC-SO-01..08 • TC-EVT-01..04 •
|
|
85
|
+
TC-LIFE-01..03 • TC-META-01 • TC-SB-01..03
|
|
86
|
+
</div>
|
|
87
|
+
</a>
|
|
88
|
+
<a
|
|
89
|
+
href="./index.html"
|
|
90
|
+
data-testid="link-main-demo"
|
|
91
|
+
class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
|
|
92
|
+
>
|
|
93
|
+
<h3 class="font-medium text-indigo-700">Main Demo App</h3>
|
|
94
|
+
<p class="text-xs text-gray-500 mt-1">
|
|
95
|
+
Original Loan Application demo with embedded and popup guests,
|
|
96
|
+
events, scripting objects.
|
|
97
|
+
</p>
|
|
98
|
+
<p class="text-xs text-gray-400 mt-2">
|
|
99
|
+
<strong>What to verify:</strong> Loan form data flows to guests.
|
|
100
|
+
Events (onLoanAmountChanged, etc.) update guest UIs. Popup guests
|
|
101
|
+
open and interact with the Loan object.
|
|
102
|
+
</p>
|
|
103
|
+
</a>
|
|
104
|
+
</div>
|
|
105
|
+
</section>
|
|
106
|
+
|
|
107
|
+
<!-- 2. CallChain & Metadata -->
|
|
108
|
+
<section class="mb-6">
|
|
109
|
+
<h2 class="text-lg font-semibold text-gray-800 border-b pb-1 mb-3">
|
|
110
|
+
2. Call Chain & Metadata Propagation
|
|
111
|
+
</h2>
|
|
112
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
113
|
+
<a
|
|
114
|
+
href="./callchain-host.html"
|
|
115
|
+
data-testid="link-callchain"
|
|
116
|
+
class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
|
|
117
|
+
>
|
|
118
|
+
<h3 class="font-medium text-indigo-700">
|
|
119
|
+
Nested CallChain Test (A → B → C)
|
|
120
|
+
</h3>
|
|
121
|
+
<p class="text-xs text-gray-500 mt-1">
|
|
122
|
+
Root Host (A) → Intermediate Guest+Host (B) → Grandchild Guest
|
|
123
|
+
(C). Verifies callContext.callChain and metadata propagation.
|
|
124
|
+
</p>
|
|
125
|
+
<p class="text-xs text-gray-400 mt-2">
|
|
126
|
+
<strong>What to verify:</strong> Click buttons in Grandchild C.
|
|
127
|
+
Host A should show <code>callContext.guest</code> = B and
|
|
128
|
+
<code>callChain</code> containing C and B with their metadata.
|
|
129
|
+
Return values should flow back to C.
|
|
130
|
+
</p>
|
|
131
|
+
<div class="mt-2 text-xs text-gray-400">
|
|
132
|
+
<strong>Test Cases:</strong> TC-CC-01..07
|
|
133
|
+
</div>
|
|
134
|
+
</a>
|
|
135
|
+
</div>
|
|
136
|
+
</section>
|
|
137
|
+
|
|
138
|
+
<!-- 3. Popup Behavior -->
|
|
139
|
+
<section class="mb-6">
|
|
140
|
+
<h2 class="text-lg font-semibold text-gray-800 border-b pb-1 mb-3">
|
|
141
|
+
3. Popup Guest Behavior
|
|
142
|
+
</h2>
|
|
143
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
144
|
+
<a
|
|
145
|
+
href="./popup-focus-host.html"
|
|
146
|
+
data-testid="link-popup-focus"
|
|
147
|
+
class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
|
|
148
|
+
>
|
|
149
|
+
<h3 class="font-medium text-indigo-700">
|
|
150
|
+
Popup Focus & Lifecycle
|
|
151
|
+
</h3>
|
|
152
|
+
<p class="text-xs text-gray-500 mt-1">
|
|
153
|
+
Open, close, and refocus popup guests. Tests trusted vs untrusted
|
|
154
|
+
domain behavior.
|
|
155
|
+
</p>
|
|
156
|
+
<p class="text-xs text-gray-400 mt-2">
|
|
157
|
+
<strong>What to verify:</strong> Trusted popups (localhost):
|
|
158
|
+
re-open brings existing popup to front. Untrusted popups: opener
|
|
159
|
+
is nulled, focus falls back to WindowProxy. Closed popup detection
|
|
160
|
+
updates guest status.
|
|
161
|
+
</p>
|
|
162
|
+
<div class="mt-2 text-xs text-gray-400">
|
|
163
|
+
<strong>Test Cases:</strong> TC-POP-01..11
|
|
164
|
+
</div>
|
|
165
|
+
</a>
|
|
166
|
+
</div>
|
|
167
|
+
</section>
|
|
168
|
+
|
|
169
|
+
<!-- 4. V1/V2 Interoperability -->
|
|
170
|
+
<section class="mb-6">
|
|
171
|
+
<h2 class="text-lg font-semibold text-gray-800 border-b pb-1 mb-3">
|
|
172
|
+
4. V1 / V2 Interoperability
|
|
173
|
+
</h2>
|
|
174
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-3">
|
|
175
|
+
<a
|
|
176
|
+
href="./v2-host-v1-guest.html"
|
|
177
|
+
data-testid="link-v2-host-v1-guest"
|
|
178
|
+
class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
|
|
179
|
+
>
|
|
180
|
+
<h3 class="font-medium text-indigo-700">V2 Host → V1 Guest</h3>
|
|
181
|
+
<p class="text-xs text-gray-500 mt-1">
|
|
182
|
+
V2 host loads V1 guest. Loan object, save flow, event feedback.
|
|
183
|
+
</p>
|
|
184
|
+
<p class="text-xs text-gray-400 mt-2">
|
|
185
|
+
<strong>What to verify:</strong> V1 guest connects, gets objects,
|
|
186
|
+
subscribes to events, and returns feedback correctly.
|
|
187
|
+
</p>
|
|
188
|
+
<div class="mt-2 text-xs text-gray-400">
|
|
189
|
+
<strong>Test Cases:</strong> TC-INTEROP-01..04
|
|
190
|
+
</div>
|
|
191
|
+
</a>
|
|
192
|
+
<a
|
|
193
|
+
href="./v2-host-v1-guest.html?nestV1GuestV2Host=true"
|
|
194
|
+
data-testid="link-v2-v1-v2-chain"
|
|
195
|
+
class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
|
|
196
|
+
>
|
|
197
|
+
<h3 class="font-medium text-indigo-700">
|
|
198
|
+
V2 Host → V1 Guest → V2 Host → V2 Guest
|
|
199
|
+
</h3>
|
|
200
|
+
<p class="text-xs text-gray-500 mt-1">
|
|
201
|
+
Full mixed-version chain. V1 guest acts as intermediate host for a
|
|
202
|
+
V2 grandchild.
|
|
203
|
+
</p>
|
|
204
|
+
<p class="text-xs text-gray-400 mt-2">
|
|
205
|
+
<strong>What to verify:</strong> Scripting objects are cloned
|
|
206
|
+
across V1/V2 boundary. Events flow through all layers.
|
|
207
|
+
</p>
|
|
208
|
+
<div class="mt-2 text-xs text-gray-400">
|
|
209
|
+
<strong>Test Cases:</strong> TC-INTEROP-05..07
|
|
210
|
+
</div>
|
|
211
|
+
</a>
|
|
212
|
+
</div>
|
|
213
|
+
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 mt-3">
|
|
214
|
+
<a
|
|
215
|
+
href="./v1-host.html"
|
|
216
|
+
data-testid="link-v1-host"
|
|
217
|
+
class="block bg-white rounded-lg shadow p-4 hover:shadow-md transition"
|
|
218
|
+
>
|
|
219
|
+
<h3 class="font-medium text-indigo-700">
|
|
220
|
+
V1 Host → V1 Guest → V2 Host → V2 Guest
|
|
221
|
+
</h3>
|
|
222
|
+
<p class="text-xs text-gray-500 mt-1">
|
|
223
|
+
Starting from V1 host. Exercises the full V1-to-V2 upgrade path.
|
|
224
|
+
</p>
|
|
225
|
+
<p class="text-xs text-gray-400 mt-2">
|
|
226
|
+
<strong>What to verify:</strong> V1 host initializes. V1 guest
|
|
227
|
+
connects. V2 host/guest chain works through V1 intermediate.
|
|
228
|
+
</p>
|
|
229
|
+
</a>
|
|
230
|
+
</div>
|
|
231
|
+
</section>
|
|
232
|
+
</main>
|
|
233
|
+
</body>
|
|
234
|
+
</html>
|
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,
|
|
@@ -93,6 +94,18 @@ class SSFHost {
|
|
|
93
94
|
* callback for guest event unsubscription
|
|
94
95
|
*/
|
|
95
96
|
#onGuestEventUnsubscribe = null;
|
|
97
|
+
/**
|
|
98
|
+
* host-supplied metadata keyed by guest id, forwarded in callChain
|
|
99
|
+
*/
|
|
100
|
+
#guestMetadata = /* @__PURE__ */ new Map();
|
|
101
|
+
/**
|
|
102
|
+
* Performance tracker for host-side timing (with dedup).
|
|
103
|
+
*/
|
|
104
|
+
#perfTracker;
|
|
105
|
+
/**
|
|
106
|
+
* Performance tracker shared by all guests (no dedup).
|
|
107
|
+
*/
|
|
108
|
+
#guestPerfTracker;
|
|
96
109
|
/**
|
|
97
110
|
* Create a new host
|
|
98
111
|
* @param hostId unique identifier for the host
|
|
@@ -104,6 +117,20 @@ class SSFHost {
|
|
|
104
117
|
if (!option?.analyticsObj) throw new Error("Analytics object is required");
|
|
105
118
|
this.#logger = option.logger;
|
|
106
119
|
this.#analyticsObj = option.analyticsObj;
|
|
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
|
+
});
|
|
107
134
|
this.#correlationId = (0, import_uuid.v4)();
|
|
108
135
|
this.#remoting = new import_microfe_common.Remoting(this.#logger, this.#correlationId);
|
|
109
136
|
if (option?.readyStateCallback && typeof option?.readyStateCallback !== "function")
|
|
@@ -127,18 +154,6 @@ class SSFHost {
|
|
|
127
154
|
);
|
|
128
155
|
});
|
|
129
156
|
};
|
|
130
|
-
#startTiming = (name, options) => {
|
|
131
|
-
this.#analyticsObj.startTiming(name, options).catch((e) => {
|
|
132
|
-
this.#logger.debug(
|
|
133
|
-
`Analytics startTiming failed: ${e.message}`
|
|
134
|
-
);
|
|
135
|
-
});
|
|
136
|
-
};
|
|
137
|
-
#endTiming = (start, options) => {
|
|
138
|
-
this.#analyticsObj.endTiming(start, options).catch((e) => {
|
|
139
|
-
this.#logger.debug(`Analytics endTiming failed: ${e.message}`);
|
|
140
|
-
});
|
|
141
|
-
};
|
|
142
157
|
#closeAllPopupGuests = () => {
|
|
143
158
|
const popupIds = Array.from(this.#guests.values()).filter((guest) => guest.openMode === import_types.OpenMode.Popup).map((guest) => guest.id);
|
|
144
159
|
popupIds.forEach((id) => this.unloadGuest(id));
|
|
@@ -204,7 +219,8 @@ class SSFHost {
|
|
|
204
219
|
guest,
|
|
205
220
|
obj,
|
|
206
221
|
functionName,
|
|
207
|
-
functionParams
|
|
222
|
+
functionParams,
|
|
223
|
+
callerChain
|
|
208
224
|
}) => {
|
|
209
225
|
const func = obj[functionName];
|
|
210
226
|
if (!(0, import_utils.isFunction)(func)) {
|
|
@@ -222,7 +238,10 @@ class SSFHost {
|
|
|
222
238
|
);
|
|
223
239
|
return new Promise((resolve) => {
|
|
224
240
|
Object.defineProperty(func, "callContext", {
|
|
225
|
-
value: {
|
|
241
|
+
value: {
|
|
242
|
+
guest,
|
|
243
|
+
...callerChain?.length ? { callChain: callerChain } : {}
|
|
244
|
+
},
|
|
226
245
|
configurable: true,
|
|
227
246
|
enumerable: true,
|
|
228
247
|
writable: true
|
|
@@ -257,7 +276,7 @@ class SSFHost {
|
|
|
257
276
|
if (!guest.ready) {
|
|
258
277
|
guest.ready = true;
|
|
259
278
|
const guestInfo = guest.getInfo();
|
|
260
|
-
this.#
|
|
279
|
+
this.#perfTracker.end("SSF.Guest.Load", {
|
|
261
280
|
appId: guestInfo.guestId,
|
|
262
281
|
appUrl: guestInfo.guestUrl
|
|
263
282
|
});
|
|
@@ -505,7 +524,7 @@ class SSFHost {
|
|
|
505
524
|
requestId,
|
|
506
525
|
body
|
|
507
526
|
}) => {
|
|
508
|
-
const { objectId } = body;
|
|
527
|
+
const { objectId, callerChain } = body;
|
|
509
528
|
const guest = this.#getGuestForWindow(sourceWin);
|
|
510
529
|
if (!guest) {
|
|
511
530
|
this.#logger.warn(
|
|
@@ -530,15 +549,20 @@ class SSFHost {
|
|
|
530
549
|
return false;
|
|
531
550
|
}
|
|
532
551
|
const guestInfo = guest.getInfo();
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
552
|
+
let timingToken;
|
|
553
|
+
if (this.#perfTracker.enabled) {
|
|
554
|
+
const name = `ScriptingObject.API.${objectId}.${body.functionName}`;
|
|
555
|
+
timingToken = this.#perfTracker.start(name, {
|
|
556
|
+
appId: guestInfo.guestId,
|
|
557
|
+
appUrl: guestInfo.guestUrl
|
|
558
|
+
});
|
|
559
|
+
}
|
|
537
560
|
this.#invoke({
|
|
538
561
|
guest,
|
|
539
562
|
obj,
|
|
540
563
|
functionName: body.functionName,
|
|
541
|
-
functionParams: body.functionParams
|
|
564
|
+
functionParams: body.functionParams,
|
|
565
|
+
callerChain
|
|
542
566
|
}).then((val) => {
|
|
543
567
|
this.#remoting.respond({
|
|
544
568
|
targetWin: sourceWin,
|
|
@@ -568,13 +592,12 @@ class SSFHost {
|
|
|
568
592
|
...guestInfo
|
|
569
593
|
});
|
|
570
594
|
}).finally(() => {
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
{
|
|
595
|
+
if (timingToken) {
|
|
596
|
+
this.#perfTracker.end(timingToken, {
|
|
574
597
|
appId: guestInfo.guestId,
|
|
575
598
|
appUrl: guestInfo.guestUrl
|
|
576
|
-
}
|
|
577
|
-
|
|
599
|
+
});
|
|
600
|
+
}
|
|
578
601
|
});
|
|
579
602
|
return true;
|
|
580
603
|
};
|
|
@@ -645,7 +668,7 @@ class SSFHost {
|
|
|
645
668
|
const guest = new import_guest.Guest({
|
|
646
669
|
...param,
|
|
647
670
|
remoting: this.#remoting,
|
|
648
|
-
|
|
671
|
+
perfTracker: this.#guestPerfTracker
|
|
649
672
|
});
|
|
650
673
|
guest.init();
|
|
651
674
|
this.#guests.set(param.guestId, guest);
|
|
@@ -717,10 +740,11 @@ class SSFHost {
|
|
|
717
740
|
let guest = this.#getGuestForUrl(url);
|
|
718
741
|
if (guest) {
|
|
719
742
|
if (!guest.window.closed) {
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
743
|
+
if ((0, import_utils.isTrustedDomain)(url)) {
|
|
744
|
+
window.open("", title);
|
|
745
|
+
} else {
|
|
746
|
+
guest.window.focus();
|
|
747
|
+
}
|
|
724
748
|
}
|
|
725
749
|
} else {
|
|
726
750
|
const windowFeatures = Object.entries({ width, height, top, left }).filter(([, v]) => v).map(([k, v]) => `${k}=${v}`).join(",");
|
|
@@ -747,7 +771,9 @@ class SSFHost {
|
|
|
747
771
|
}
|
|
748
772
|
}, 0);
|
|
749
773
|
}
|
|
750
|
-
|
|
774
|
+
if (!(0, import_utils.isTrustedDomain)(url)) {
|
|
775
|
+
guestWindow.opener = null;
|
|
776
|
+
}
|
|
751
777
|
guest = this.#attachGuest({
|
|
752
778
|
guestId,
|
|
753
779
|
window: guestWindow,
|
|
@@ -914,6 +940,22 @@ class SSFHost {
|
|
|
914
940
|
} else if ((0, import_utils.isFunction)(propValue)) {
|
|
915
941
|
Object.defineProperty(so, propName, {
|
|
916
942
|
value: async (...args) => {
|
|
943
|
+
const callerCtx = so[propName]?.callContext;
|
|
944
|
+
if (callerCtx?.guest) {
|
|
945
|
+
const existingChain = callerCtx.callChain ?? [];
|
|
946
|
+
const guestId = callerCtx.guest.id;
|
|
947
|
+
const meta = this.#guestMetadata.get(guestId);
|
|
948
|
+
const callerEntry = { id: guestId };
|
|
949
|
+
if (meta) callerEntry.metadata = meta;
|
|
950
|
+
Object.defineProperty(propValue, "callContext", {
|
|
951
|
+
value: {
|
|
952
|
+
callChain: [...existingChain, callerEntry]
|
|
953
|
+
},
|
|
954
|
+
configurable: true,
|
|
955
|
+
enumerable: true,
|
|
956
|
+
writable: true
|
|
957
|
+
});
|
|
958
|
+
}
|
|
917
959
|
const retVal = await propValue(...args);
|
|
918
960
|
return (0, import_microfe_common.isScriptingObjectProxy)(retVal) ? this.cloneScriptingObject(retVal) : retVal;
|
|
919
961
|
},
|
|
@@ -948,6 +990,7 @@ class SSFHost {
|
|
|
948
990
|
this.#popupGuestMonitor = null;
|
|
949
991
|
}
|
|
950
992
|
this.#closeAllPopupGuests();
|
|
993
|
+
this.#guestMetadata.clear();
|
|
951
994
|
this.#remoting.close();
|
|
952
995
|
window.removeEventListener("beforeunload", this.#closeAllPopupGuests);
|
|
953
996
|
this.#logger.debug(
|
|
@@ -998,20 +1041,16 @@ class SSFHost {
|
|
|
998
1041
|
};
|
|
999
1042
|
}
|
|
1000
1043
|
const guestPromises = [];
|
|
1001
|
-
let
|
|
1044
|
+
let eventTimingToken;
|
|
1002
1045
|
const dispatchToGuest = (guest) => {
|
|
1003
1046
|
const guestInfo = guest.getInfo();
|
|
1004
1047
|
if (timeout && guest?.capabilities?.eventFeedback) {
|
|
1005
1048
|
guestPromises.push(guest.dispatchEvent(eventObj, timeout));
|
|
1006
|
-
if (!
|
|
1007
|
-
this.#
|
|
1049
|
+
if (!eventTimingToken && this.#perfTracker.enabled) {
|
|
1050
|
+
eventTimingToken = this.#perfTracker.start(
|
|
1008
1051
|
`ScriptingObject.Event.${scriptingObject.id}.${name}`,
|
|
1009
|
-
{
|
|
1010
|
-
appId: this.hostId,
|
|
1011
|
-
appUrl: window.location.href
|
|
1012
|
-
}
|
|
1052
|
+
{ appId: this.hostId, appUrl: window.location.href }
|
|
1013
1053
|
);
|
|
1014
|
-
timingMetricStarted = true;
|
|
1015
1054
|
}
|
|
1016
1055
|
this.#logger.debug({
|
|
1017
1056
|
message: "Event dispatched and awaiting feedback",
|
|
@@ -1035,7 +1074,7 @@ class SSFHost {
|
|
|
1035
1074
|
} else {
|
|
1036
1075
|
this.#guests.forEach(dispatchToGuest);
|
|
1037
1076
|
}
|
|
1038
|
-
|
|
1077
|
+
return Promise.all(guestPromises).then((values) => {
|
|
1039
1078
|
this.#logger.debug({
|
|
1040
1079
|
message: "Event feedback received",
|
|
1041
1080
|
scriptingEventId: id
|
|
@@ -1049,16 +1088,13 @@ class SSFHost {
|
|
|
1049
1088
|
});
|
|
1050
1089
|
throw ex;
|
|
1051
1090
|
}).finally(() => {
|
|
1052
|
-
if (
|
|
1053
|
-
this.#
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
}
|
|
1059
|
-
);
|
|
1091
|
+
if (eventTimingToken) {
|
|
1092
|
+
this.#perfTracker.end(eventTimingToken, {
|
|
1093
|
+
appId: this.hostId,
|
|
1094
|
+
appUrl: window.location.href
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1060
1097
|
});
|
|
1061
|
-
return retValue;
|
|
1062
1098
|
};
|
|
1063
1099
|
/**
|
|
1064
1100
|
* get reference to all guest applications
|
|
@@ -1086,7 +1122,8 @@ class SSFHost {
|
|
|
1086
1122
|
searchParams = {},
|
|
1087
1123
|
onLoad,
|
|
1088
1124
|
onError,
|
|
1089
|
-
options = {}
|
|
1125
|
+
options = {},
|
|
1126
|
+
metadata
|
|
1090
1127
|
} = param;
|
|
1091
1128
|
if (!guestId) throw new Error("id for guest application is required");
|
|
1092
1129
|
let instanceId = guestId;
|
|
@@ -1100,7 +1137,7 @@ class SSFHost {
|
|
|
1100
1137
|
const { openMode = import_types.OpenMode.Embed, popupWindowFeatures = {} } = options;
|
|
1101
1138
|
const srcUrl = this.#getGuestUrl(url, searchParams);
|
|
1102
1139
|
let guest = null;
|
|
1103
|
-
this.#
|
|
1140
|
+
this.#perfTracker.start("SSF.Guest.Load", {
|
|
1104
1141
|
appId: instanceId,
|
|
1105
1142
|
appUrl: srcUrl
|
|
1106
1143
|
});
|
|
@@ -1128,6 +1165,7 @@ class SSFHost {
|
|
|
1128
1165
|
} else {
|
|
1129
1166
|
throw new Error(`Invalid openMode: ${openMode}`);
|
|
1130
1167
|
}
|
|
1168
|
+
if (metadata) this.#guestMetadata.set(instanceId, metadata);
|
|
1131
1169
|
this.#logger.audit({
|
|
1132
1170
|
message: "Guest loaded",
|
|
1133
1171
|
...guest.getInfo()
|
|
@@ -1193,6 +1231,7 @@ class SSFHost {
|
|
|
1193
1231
|
guest.dispose();
|
|
1194
1232
|
this.#guestsByWindow.delete(guest.window);
|
|
1195
1233
|
this.#guestsByUrl.delete(guest.url);
|
|
1234
|
+
this.#guestMetadata.delete(guest.id);
|
|
1196
1235
|
this.#guests.delete(guest.id);
|
|
1197
1236
|
this.#logger.audit({
|
|
1198
1237
|
message: `Guest is removed from host`,
|