@elliemae/pui-app-bridge 2.9.9 → 2.16.6
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/appBridge.js +380 -93
- package/dist/cjs/appRegistry.js +136 -0
- package/dist/cjs/config/app.js +15 -2
- package/dist/cjs/config/microFE.js +3 -3
- package/dist/cjs/eventManager.js +16 -16
- package/dist/cjs/frame.html +2 -2
- package/dist/cjs/frame.js +39 -14
- package/dist/cjs/index.html +1 -1
- package/dist/cjs/loaders/script.js +5 -5
- package/dist/cjs/loaders/style.js +1 -0
- package/dist/cjs/microfeHost.js +51 -31
- package/dist/cjs/tests/flights/23.1/app.checksum1.js +25 -24
- package/dist/cjs/tests/flights/latest/app.checksum.js +25 -24
- package/dist/cjs/tests/hotels/23.1/app.checksum.js +27 -24
- package/dist/cjs/tests/hotels/latest/app.checksum.js +27 -24
- package/dist/cjs/tests/loan/latest/index.js +49 -57
- package/dist/cjs/tests/scriptingObjects/analytics.js +7 -7
- package/dist/cjs/tests/scriptingObjects/appraisalServiceModule.js +8 -8
- package/dist/cjs/tests/scriptingObjects/global.js +1 -2
- package/dist/cjs/tests/task/latest/index.dev.js +29 -28
- package/dist/cjs/tests/task/latest/index.js +29 -28
- package/dist/cjs/tests/travelhub/23.1/app.checksum.js +24 -26
- package/dist/cjs/tests/travelhub/23.1/landing.checksum1.js +5 -7
- package/dist/cjs/utils.js +31 -1
- package/dist/esm/appBridge.js +390 -95
- package/dist/esm/appRegistry.js +116 -0
- package/dist/esm/config/app.js +15 -2
- package/dist/esm/config/microFE.js +3 -3
- package/dist/esm/eventManager.js +16 -16
- package/dist/esm/frame.html +2 -2
- package/dist/esm/frame.js +29 -14
- package/dist/esm/index.html +1 -1
- package/dist/esm/loaders/script.js +5 -5
- package/dist/esm/loaders/style.js +1 -0
- package/dist/esm/microfeHost.js +55 -31
- package/dist/esm/tests/flights/23.1/app.checksum1.js +25 -24
- package/dist/esm/tests/flights/latest/app.checksum.js +25 -24
- package/dist/esm/tests/hotels/23.1/app.checksum.js +27 -24
- package/dist/esm/tests/hotels/latest/app.checksum.js +27 -24
- package/dist/esm/tests/loan/latest/index.js +49 -57
- package/dist/esm/tests/scriptingObjects/analytics.js +7 -7
- package/dist/esm/tests/scriptingObjects/appraisalServiceModule.js +8 -8
- package/dist/esm/tests/scriptingObjects/global.js +1 -2
- package/dist/esm/tests/task/latest/index.dev.js +29 -28
- package/dist/esm/tests/task/latest/index.js +29 -28
- package/dist/esm/tests/travelhub/23.1/app.checksum.js +24 -26
- package/dist/esm/tests/travelhub/23.1/landing.checksum1.js +5 -7
- package/dist/esm/utils.js +31 -1
- package/dist/public/assets/frame.671d9de68be598da64ca.html +47 -0
- package/dist/public/creditService/latest/creditService.checksum.js.gz +0 -0
- package/dist/public/frame.html +1 -1
- package/dist/public/guest/businessObjects.js.gz +0 -0
- package/dist/public/guest/util.js.gz +0 -0
- package/dist/public/index.html +1 -1
- package/dist/public/init.js.gz +0 -0
- package/dist/public/js/emuiAppBridge.40c8880c94dbc97b49fd.js +51 -0
- package/dist/public/js/emuiAppBridge.40c8880c94dbc97b49fd.js.br +0 -0
- package/dist/public/js/emuiAppBridge.40c8880c94dbc97b49fd.js.gz +0 -0
- package/dist/public/js/emuiAppBridge.40c8880c94dbc97b49fd.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/loanValidation/latest/loanValidation.checksum.js.gz +0 -0
- package/dist/public/pricingService/latest/pricingService.checksum.js.gz +0 -0
- package/dist/public/utils.js.gz +0 -0
- package/dist/types/lib/appBridge.d.ts +38 -28
- package/dist/types/lib/appRegistry.d.ts +41 -0
- package/dist/types/lib/eventManager.d.ts +4 -4
- package/dist/types/lib/frame.d.ts +45 -4
- package/dist/types/lib/index.d.ts +3 -3
- package/dist/types/lib/loaders/script.d.ts +2 -1
- package/dist/types/lib/microfeHost.d.ts +15 -25
- package/dist/types/lib/tests/flights/23.1/app.checksum1.d.ts +7 -0
- package/dist/types/lib/tests/flights/latest/app.checksum.d.ts +7 -0
- package/dist/types/lib/tests/hotels/23.1/app.checksum.d.ts +7 -0
- package/dist/types/lib/tests/hotels/latest/app.checksum.d.ts +7 -0
- package/dist/types/lib/tests/loan/latest/index.d.ts +11 -0
- package/dist/types/lib/tests/scriptingObjects/analytics.d.ts +3 -3
- package/dist/types/lib/tests/scriptingObjects/appraisalServiceModule.d.ts +2 -1
- package/dist/types/lib/tests/task/latest/index.d.ts +10 -0
- package/dist/types/lib/tests/task/latest/index.dev.d.ts +10 -0
- package/dist/types/lib/tests/travelhub/23.1/app.checksum.d.ts +7 -0
- package/dist/types/lib/tests/travelhub/23.1/landing.checksum1.d.ts +2 -0
- package/dist/types/lib/typings/appInfo.d.ts +1 -0
- package/dist/types/lib/typings/common.d.ts +0 -66
- package/dist/types/lib/typings/guest.d.ts +10 -3
- package/dist/types/lib/typings/host.d.ts +32 -32
- package/dist/types/lib/typings/window.d.ts +6 -1
- package/dist/types/lib/utils.d.ts +7 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dist/umd/671d9de68be598da64ca.html +47 -0
- package/dist/umd/creditService/latest/creditService.checksum.js.gz +0 -0
- package/dist/umd/frame.html +1 -1
- package/dist/umd/guest/businessObjects.js.gz +0 -0
- package/dist/umd/guest/util.js.gz +0 -0
- package/dist/umd/index.html +1 -1
- package/dist/umd/index.js +35 -9
- 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.gz +0 -0
- 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/loanValidation/latest/loanValidation.checksum.js.gz +0 -0
- package/dist/umd/pricingService/latest/pricingService.checksum.js.gz +0 -0
- package/dist/umd/utils.js.gz +0 -0
- package/package.json +9 -12
- package/dist/public/js/emuiAppBridge.530390c3bb03f32357f7.js +0 -25
- package/dist/public/js/emuiAppBridge.530390c3bb03f32357f7.js.br +0 -0
- package/dist/public/js/emuiAppBridge.530390c3bb03f32357f7.js.gz +0 -0
- package/dist/public/js/emuiAppBridge.530390c3bb03f32357f7.js.map +0 -1
- package/dist/types/lib/tests/pubsubAPI.test.d.ts +0 -1
package/dist/esm/appBridge.js
CHANGED
|
@@ -1,45 +1,120 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { throttle } from "lodash";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
3
|
+
import {
|
|
4
|
+
ScriptingObjectNames
|
|
5
|
+
} from "@elliemae/pui-scripting-object";
|
|
6
|
+
import {
|
|
7
|
+
ProxyEvent,
|
|
8
|
+
Event,
|
|
9
|
+
ScriptingObjectManager,
|
|
10
|
+
ScriptingObject,
|
|
11
|
+
isScriptingObjectProxy
|
|
12
|
+
} from "@elliemae/microfe-common";
|
|
3
13
|
import { EventManager } from "./eventManager.js";
|
|
4
|
-
import { Frame } from "./frame.js";
|
|
14
|
+
import { Frame, FRAME_APP_CONTAINER_ID_PREFIX } from "./frame.js";
|
|
5
15
|
import { getCurrentBreakpoint, getViewportSize } from "./typings/window.js";
|
|
6
16
|
import { CAppConfig } from "./config/app.js";
|
|
7
17
|
import { CMicroFEConfig } from "./config/microFE.js";
|
|
8
18
|
import { StyleLoader, ScriptLoader, ManifestLoader } from "./loaders/index.js";
|
|
9
19
|
import { CMicroFEHost } from "./microfeHost.js";
|
|
10
|
-
|
|
20
|
+
import { CAppRegistry } from "./appRegistry.js";
|
|
21
|
+
const KEEP_ALIVE_INTERVAL = 12e4;
|
|
22
|
+
const userInteractionEvents = ["click", "scroll", "keypress", "touchstart"];
|
|
11
23
|
const cssType = /\.css$/;
|
|
12
24
|
const isCss = (fileName) => cssType.test(fileName);
|
|
13
25
|
class CAppBridge {
|
|
26
|
+
/**
|
|
27
|
+
* instance of the pui diagnostics logger
|
|
28
|
+
*/
|
|
14
29
|
#logger;
|
|
30
|
+
/**
|
|
31
|
+
* release version of the product
|
|
32
|
+
*/
|
|
15
33
|
#version;
|
|
34
|
+
/**
|
|
35
|
+
* instance of the script loader
|
|
36
|
+
*/
|
|
16
37
|
#scriptLoader;
|
|
38
|
+
/**
|
|
39
|
+
* instance of the style loader
|
|
40
|
+
*/
|
|
17
41
|
#styleLoader;
|
|
42
|
+
/**
|
|
43
|
+
* instance of the app config
|
|
44
|
+
*/
|
|
18
45
|
#appConfig;
|
|
46
|
+
/**
|
|
47
|
+
* instance of the micro frontend config
|
|
48
|
+
*/
|
|
19
49
|
#microFEConfig = new CMicroFEConfig();
|
|
50
|
+
/**
|
|
51
|
+
* instance of the scripting object manager
|
|
52
|
+
*/
|
|
20
53
|
#soManager;
|
|
54
|
+
/**
|
|
55
|
+
* instance of the event manager
|
|
56
|
+
*/
|
|
21
57
|
#eventManager;
|
|
58
|
+
/**
|
|
59
|
+
* list of active apps
|
|
60
|
+
*/
|
|
22
61
|
#activeApps = /* @__PURE__ */ new Map();
|
|
62
|
+
/**
|
|
63
|
+
* instance of the app registry
|
|
64
|
+
*/
|
|
65
|
+
#appRegistry = new CAppRegistry();
|
|
66
|
+
/**
|
|
67
|
+
* flag to extend parent session when user interacts with the guest application
|
|
68
|
+
*/
|
|
69
|
+
#extendSession = true;
|
|
23
70
|
/**
|
|
24
71
|
* Create a new instance of the AppBridge
|
|
25
|
-
* @param {AppBridgeParams}
|
|
72
|
+
* @param {AppBridgeParams} options - App Bridge constructor parameters
|
|
26
73
|
*/
|
|
27
|
-
constructor(
|
|
28
|
-
const { logger } =
|
|
74
|
+
constructor(options) {
|
|
75
|
+
const { logger } = options;
|
|
29
76
|
if (!logger) throw new Error("logger is required");
|
|
30
|
-
this.#logger =
|
|
31
|
-
this.#version =
|
|
77
|
+
this.#logger = options.logger;
|
|
78
|
+
this.#version = options.version;
|
|
79
|
+
this.#extendSession = options.extendSession ?? true;
|
|
32
80
|
this.#appConfig = new CAppConfig({
|
|
33
|
-
version:
|
|
34
|
-
baseUrl:
|
|
81
|
+
version: options.version,
|
|
82
|
+
baseUrl: options.appConfigBaseUrl
|
|
35
83
|
});
|
|
36
84
|
this.#scriptLoader = new ScriptLoader(logger);
|
|
37
85
|
this.#styleLoader = new StyleLoader(logger);
|
|
38
86
|
this.#soManager = new ScriptingObjectManager();
|
|
39
87
|
this.#eventManager = new EventManager();
|
|
40
88
|
}
|
|
41
|
-
#
|
|
42
|
-
|
|
89
|
+
#isFunction(value) {
|
|
90
|
+
return typeof value === "function";
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* check if the value is a proxy event
|
|
94
|
+
* @param value
|
|
95
|
+
* @returns
|
|
96
|
+
*/
|
|
97
|
+
#isProxyEvent = (value) => (
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
99
|
+
value instanceof ProxyEvent || // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
100
|
+
typeof value?.subscribe === "function"
|
|
101
|
+
);
|
|
102
|
+
// support v1 scripting objects
|
|
103
|
+
/**
|
|
104
|
+
* format error message for app not found
|
|
105
|
+
* @param id app id
|
|
106
|
+
* @param instanceId unique instance id
|
|
107
|
+
* @returns error message
|
|
108
|
+
*/
|
|
109
|
+
#getAppNotFoundError = (id, instanceId) => `Application ${id} with instance id ${instanceId} is not found. Most probably the appId property of app.config.json is not set to ${id}`;
|
|
110
|
+
/**
|
|
111
|
+
* remove assets from DOM
|
|
112
|
+
* @param instanceId unique instance id of the app
|
|
113
|
+
* @param documentEle document element of the app
|
|
114
|
+
* @returns void
|
|
115
|
+
*/
|
|
116
|
+
#removeAssetsFromDOM = (instanceId, documentEle = document) => {
|
|
117
|
+
const { elementIds } = this.#activeApps.get(instanceId) || {};
|
|
43
118
|
if (elementIds) {
|
|
44
119
|
elementIds.forEach((elementId) => {
|
|
45
120
|
const ele = documentEle.getElementById(elementId);
|
|
@@ -47,9 +122,26 @@ class CAppBridge {
|
|
|
47
122
|
});
|
|
48
123
|
}
|
|
49
124
|
};
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
125
|
+
/**
|
|
126
|
+
* add app to active app list
|
|
127
|
+
* @param param0
|
|
128
|
+
* @param param0.id
|
|
129
|
+
* @param param0.instanceId
|
|
130
|
+
* @param elementIds
|
|
131
|
+
* @param param0.documentEle
|
|
132
|
+
*/
|
|
133
|
+
#addAppToActiveAppList = ({
|
|
134
|
+
id,
|
|
135
|
+
instanceId,
|
|
136
|
+
documentEle
|
|
137
|
+
}, elementIds) => {
|
|
138
|
+
const app = this.#appRegistry.get({ id, instanceId });
|
|
139
|
+
if (!app) {
|
|
140
|
+
throw new Error(this.#getAppNotFoundError(id, instanceId));
|
|
141
|
+
}
|
|
142
|
+
this.#activeApps.set(instanceId, {
|
|
143
|
+
id,
|
|
144
|
+
instanceId,
|
|
53
145
|
elementIds,
|
|
54
146
|
guest: {
|
|
55
147
|
guestWindow: documentEle?.defaultView,
|
|
@@ -60,29 +152,37 @@ class CAppBridge {
|
|
|
60
152
|
#waitAndInitApplication = (options, requests) => {
|
|
61
153
|
const {
|
|
62
154
|
id,
|
|
155
|
+
instanceId,
|
|
156
|
+
containerId,
|
|
63
157
|
name,
|
|
64
158
|
hostUrl,
|
|
65
159
|
manifestPath,
|
|
66
160
|
homeRoute,
|
|
161
|
+
initialRoute,
|
|
67
162
|
history,
|
|
68
163
|
theme,
|
|
69
164
|
documentEle
|
|
70
165
|
} = options;
|
|
71
|
-
return Promise.all(requests).then(
|
|
166
|
+
return Promise.all(requests).then(
|
|
167
|
+
this.#addAppToActiveAppList.bind(null, { id, instanceId, documentEle })
|
|
168
|
+
).then(
|
|
72
169
|
this.#initApplication.bind(null, {
|
|
73
170
|
id,
|
|
171
|
+
instanceId,
|
|
172
|
+
containerId,
|
|
74
173
|
name,
|
|
75
174
|
hostUrl,
|
|
76
175
|
manifestPath,
|
|
77
176
|
homeRoute,
|
|
177
|
+
initialRoute,
|
|
78
178
|
history,
|
|
79
179
|
theme
|
|
80
180
|
})
|
|
81
181
|
).catch((err) => {
|
|
82
|
-
const message = `Application load failed. Unable to load one or more resources for
|
|
182
|
+
const message = `Application load failed. Unable to load one or more resources for ${options.id} with instance id ${instanceId}. ${err.message}`;
|
|
83
183
|
this.#logger.error({
|
|
84
184
|
message,
|
|
85
|
-
appId:
|
|
185
|
+
appId: id,
|
|
86
186
|
exception: err
|
|
87
187
|
});
|
|
88
188
|
throw new Error(message);
|
|
@@ -90,28 +190,31 @@ class CAppBridge {
|
|
|
90
190
|
};
|
|
91
191
|
#initApplication = async ({
|
|
92
192
|
id,
|
|
93
|
-
|
|
193
|
+
instanceId,
|
|
194
|
+
containerId,
|
|
94
195
|
hostUrl,
|
|
95
196
|
manifestPath,
|
|
96
197
|
homeRoute,
|
|
198
|
+
initialRoute,
|
|
97
199
|
history,
|
|
98
200
|
theme
|
|
99
201
|
}) => {
|
|
100
|
-
const app =
|
|
202
|
+
const app = this.#appRegistry.get({ id, instanceId });
|
|
101
203
|
if (!app) {
|
|
102
204
|
throw new Error(
|
|
103
|
-
`Application ${
|
|
205
|
+
`Application ${id} with instance id ${instanceId} is not found. Most probably the appId property of app.config.json is not set to ${id}`
|
|
104
206
|
);
|
|
105
207
|
}
|
|
106
208
|
if (!app.init || typeof app.init !== "function")
|
|
107
209
|
throw new Error(
|
|
108
|
-
`Application ${
|
|
210
|
+
`Application ${id} with instance id ${instanceId} doesn't expose init method`
|
|
109
211
|
);
|
|
110
212
|
const host = new CMicroFEHost({
|
|
111
213
|
guest: {
|
|
112
214
|
id
|
|
113
215
|
},
|
|
114
216
|
version: this.#version,
|
|
217
|
+
containerId,
|
|
115
218
|
logger: this.#logger,
|
|
116
219
|
soManager: this.#soManager,
|
|
117
220
|
eventManager: this.#eventManager
|
|
@@ -121,6 +224,7 @@ class CAppBridge {
|
|
|
121
224
|
hostUrl,
|
|
122
225
|
manifestPath,
|
|
123
226
|
homeRoute,
|
|
227
|
+
initialRoute,
|
|
124
228
|
prevState: null,
|
|
125
229
|
history,
|
|
126
230
|
theme,
|
|
@@ -130,8 +234,10 @@ class CAppBridge {
|
|
|
130
234
|
});
|
|
131
235
|
};
|
|
132
236
|
#loadApp = async (options) => {
|
|
133
|
-
const { id, files, name, hostUrl, documentEle } = options;
|
|
134
|
-
this.#logger.debug(
|
|
237
|
+
const { id, instanceId, files, name, hostUrl, documentEle, isJsModule } = options;
|
|
238
|
+
this.#logger.debug(
|
|
239
|
+
`Application ${id} with instance id ${instanceId} is loading...`
|
|
240
|
+
);
|
|
135
241
|
let assets = files;
|
|
136
242
|
const manifest = await ManifestLoader.get(options);
|
|
137
243
|
assets = ManifestLoader.getFullFileNameofAssets(manifest, files);
|
|
@@ -143,55 +249,191 @@ class CAppBridge {
|
|
|
143
249
|
hostUrl,
|
|
144
250
|
documentEle,
|
|
145
251
|
fileName,
|
|
146
|
-
index: counter
|
|
252
|
+
index: counter,
|
|
253
|
+
isJsModule
|
|
147
254
|
};
|
|
148
255
|
return !isCss(fileName) ? this.#scriptLoader.add(resourceOptions) : this.#styleLoader.add(resourceOptions);
|
|
149
256
|
});
|
|
150
257
|
await this.#waitAndInitApplication(options, requests);
|
|
151
|
-
this.#logger.audit(
|
|
258
|
+
this.#logger.audit(
|
|
259
|
+
`Application ${id} with instance id ${instanceId} loaded`
|
|
260
|
+
);
|
|
152
261
|
};
|
|
153
|
-
#unloadApp = ({ id, hostUrl, documentEle }) => {
|
|
154
|
-
this.#logger.debug(
|
|
155
|
-
|
|
262
|
+
#unloadApp = ({ id, instanceId, hostUrl, documentEle }) => {
|
|
263
|
+
this.#logger.debug(
|
|
264
|
+
`Application ${id} with instance id ${instanceId} unloading...`
|
|
265
|
+
);
|
|
266
|
+
const app = this.#appRegistry.get({
|
|
267
|
+
id,
|
|
268
|
+
instanceId
|
|
269
|
+
});
|
|
156
270
|
if (!app) return;
|
|
157
|
-
this.#removeAssetsFromDOM(
|
|
271
|
+
this.#removeAssetsFromDOM(instanceId, documentEle);
|
|
158
272
|
this.#scriptLoader.removeDynamicImportedScripts(hostUrl, documentEle);
|
|
159
273
|
this.#scriptLoader.removePrefetchLinks(hostUrl, documentEle);
|
|
160
274
|
this.#styleLoader.removeDynamicImportedStyles(hostUrl, documentEle);
|
|
161
|
-
|
|
162
|
-
this.#
|
|
163
|
-
|
|
275
|
+
this.#appRegistry.delete({ id, instanceId });
|
|
276
|
+
this.#logger.audit(
|
|
277
|
+
`Application ${id} with instance id ${instanceId} unloaded`
|
|
278
|
+
);
|
|
164
279
|
};
|
|
165
|
-
#mountApp = async ({ id,
|
|
166
|
-
const app =
|
|
280
|
+
#mountApp = async ({ id, instanceId }) => {
|
|
281
|
+
const app = this.#appRegistry.get({ id, instanceId });
|
|
167
282
|
if (!app?.mount || typeof app?.mount !== "function")
|
|
168
283
|
throw new Error(
|
|
169
|
-
`Application ${
|
|
284
|
+
`Application ${id} with instance id ${instanceId} doesn't expose mount method`
|
|
170
285
|
);
|
|
171
286
|
return app.mount({
|
|
172
|
-
containerId: `${
|
|
287
|
+
containerId: `${FRAME_APP_CONTAINER_ID_PREFIX}${id}`,
|
|
173
288
|
hostBreakpoint: getCurrentBreakpoint(),
|
|
174
289
|
hostViewportSize: getViewportSize()
|
|
175
290
|
});
|
|
176
291
|
};
|
|
177
|
-
#unmountApp = ({ id,
|
|
178
|
-
const app =
|
|
292
|
+
#unmountApp = ({ id, instanceId }) => {
|
|
293
|
+
const app = this.#appRegistry.get({ id, instanceId });
|
|
179
294
|
if (!app?.unmount) return null;
|
|
180
295
|
if (typeof app.unmount !== "function")
|
|
181
296
|
throw new Error(
|
|
182
|
-
`Application ${
|
|
297
|
+
`Application ${id} with instance id ${instanceId} doesn't expose unmount method`
|
|
183
298
|
);
|
|
184
299
|
return app.unmount({
|
|
185
|
-
containerId: `${
|
|
300
|
+
containerId: `${FRAME_APP_CONTAINER_ID_PREFIX}${id}`
|
|
186
301
|
});
|
|
187
302
|
};
|
|
303
|
+
/**
|
|
304
|
+
* manage session for the guest application by calling the keepSessionAlive method exposed by parent
|
|
305
|
+
* @param root0
|
|
306
|
+
* @param root0.id
|
|
307
|
+
* @param root0.instanceId
|
|
308
|
+
*/
|
|
309
|
+
#manageSession = ({ id, instanceId }) => {
|
|
310
|
+
if (!this.#extendSession) return;
|
|
311
|
+
try {
|
|
312
|
+
const appObj = this.#soManager.getObject(
|
|
313
|
+
ScriptingObjectNames.Application
|
|
314
|
+
);
|
|
315
|
+
if (!appObj) {
|
|
316
|
+
this.#logger.warn({
|
|
317
|
+
message: `Application scripting object not available for ${id} to manage session`
|
|
318
|
+
});
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const app = this.#activeApps.get(instanceId);
|
|
322
|
+
if (!app) return;
|
|
323
|
+
app.keepAlive = throttle(
|
|
324
|
+
async () => {
|
|
325
|
+
try {
|
|
326
|
+
await appObj.keepSessionAlive();
|
|
327
|
+
} catch (e) {
|
|
328
|
+
this.#logger.error(
|
|
329
|
+
`Error keeping session alive. ${e.message}`
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
KEEP_ALIVE_INTERVAL
|
|
334
|
+
// throttle time
|
|
335
|
+
);
|
|
336
|
+
const frameEle = Frame.get(instanceId);
|
|
337
|
+
userInteractionEvents.forEach((eventType) => {
|
|
338
|
+
frameEle?.contentDocument?.addEventListener(eventType, app.keepAlive);
|
|
339
|
+
});
|
|
340
|
+
} catch (err) {
|
|
341
|
+
this.#logger.warn({
|
|
342
|
+
message: `Application scripting object not available for ${id} to manage session`,
|
|
343
|
+
exception: err
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
/**
|
|
348
|
+
* clear session management for the guest application
|
|
349
|
+
* @param instanceId unique instance id of the application
|
|
350
|
+
* @param app
|
|
351
|
+
* @returns
|
|
352
|
+
*/
|
|
353
|
+
#clearSession = (app) => {
|
|
354
|
+
if (!this.#extendSession || !app) return;
|
|
355
|
+
const { keepAlive } = app;
|
|
356
|
+
if (keepAlive) {
|
|
357
|
+
userInteractionEvents.forEach((eventType) => {
|
|
358
|
+
document.removeEventListener(eventType, keepAlive);
|
|
359
|
+
});
|
|
360
|
+
app.keepAlive?.cancel();
|
|
361
|
+
}
|
|
362
|
+
};
|
|
188
363
|
/**
|
|
189
364
|
* registers scripting object to the host
|
|
190
365
|
* @param {ValueOf<AppObjects>} so scripting object
|
|
191
366
|
* @param {AddScriptingObjectParams} params params to add scripting object
|
|
192
367
|
*/
|
|
193
368
|
addScriptingObject = (so, params) => {
|
|
194
|
-
|
|
369
|
+
if (isScriptingObjectProxy(so)) {
|
|
370
|
+
const clonedSo = this.cloneScriptingObject(so);
|
|
371
|
+
this.#soManager.addScriptingObject(clonedSo, params);
|
|
372
|
+
} else {
|
|
373
|
+
this.#soManager.addScriptingObject(so, params);
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
/**
|
|
377
|
+
* Create new Scripting Object from SSF scripting object proxy
|
|
378
|
+
* @param proxy - reference to the scripting object obtained through getObject method
|
|
379
|
+
* @returns cloned version of the scripting object
|
|
380
|
+
*/
|
|
381
|
+
cloneScriptingObject = (proxy) => {
|
|
382
|
+
if (!proxy) throw new Error("proxy is required");
|
|
383
|
+
const so = new ScriptingObject(proxy.id, proxy.objectType);
|
|
384
|
+
let unsubscribers = [];
|
|
385
|
+
Object.keys(proxy).forEach((propName) => {
|
|
386
|
+
const propValue = proxy[propName];
|
|
387
|
+
if (this.#isProxyEvent(propValue)) {
|
|
388
|
+
const event = new Event({
|
|
389
|
+
name: propValue.name || propName,
|
|
390
|
+
objectId: so.id
|
|
391
|
+
});
|
|
392
|
+
Object.defineProperty(so, propName, {
|
|
393
|
+
value: event,
|
|
394
|
+
enumerable: true
|
|
395
|
+
});
|
|
396
|
+
const listener = ({
|
|
397
|
+
eventParams,
|
|
398
|
+
eventOptions
|
|
399
|
+
}) => this.dispatchEvent({
|
|
400
|
+
event,
|
|
401
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
402
|
+
eventParams,
|
|
403
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
404
|
+
eventOptions
|
|
405
|
+
});
|
|
406
|
+
const token = propValue.subscribe(listener);
|
|
407
|
+
unsubscribers.push(() => {
|
|
408
|
+
propValue.unsubscribe(token);
|
|
409
|
+
});
|
|
410
|
+
} else if (this.#isFunction(propValue)) {
|
|
411
|
+
Object.defineProperty(so, propName, {
|
|
412
|
+
value: async (...args) => {
|
|
413
|
+
const retVal = await propValue(...args);
|
|
414
|
+
return isScriptingObjectProxy(retVal) ? this.cloneScriptingObject(retVal) : retVal;
|
|
415
|
+
},
|
|
416
|
+
enumerable: true
|
|
417
|
+
});
|
|
418
|
+
if (propName === "dispose") {
|
|
419
|
+
const defaultImpl = so.dispose;
|
|
420
|
+
Object.defineProperty(so, propName, {
|
|
421
|
+
value: () => {
|
|
422
|
+
so._dispose();
|
|
423
|
+
return defaultImpl.apply(so);
|
|
424
|
+
},
|
|
425
|
+
enumerable: true
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
so._dispose = () => {
|
|
431
|
+
unsubscribers.forEach((unsub) => {
|
|
432
|
+
unsub?.();
|
|
433
|
+
});
|
|
434
|
+
unsubscribers = [];
|
|
435
|
+
};
|
|
436
|
+
return so;
|
|
195
437
|
};
|
|
196
438
|
/**
|
|
197
439
|
* Close all active guest micro frontend applications
|
|
@@ -201,43 +443,68 @@ class CAppBridge {
|
|
|
201
443
|
};
|
|
202
444
|
/**
|
|
203
445
|
* Close guest micro frontend application
|
|
204
|
-
* @param
|
|
446
|
+
* @param instanceId unique instance id of the application
|
|
205
447
|
*/
|
|
206
|
-
closeApp = async (
|
|
207
|
-
if (!
|
|
208
|
-
const
|
|
209
|
-
if (!
|
|
210
|
-
|
|
448
|
+
closeApp = async (instanceId) => {
|
|
449
|
+
if (!instanceId) throw new Error("instanceId is required");
|
|
450
|
+
const app = this.#activeApps.get(instanceId);
|
|
451
|
+
if (!app) {
|
|
452
|
+
this.#logger.warn(
|
|
453
|
+
`Application with instance id ${instanceId} is not found`
|
|
454
|
+
);
|
|
455
|
+
return;
|
|
211
456
|
}
|
|
212
|
-
|
|
457
|
+
this.#activeApps.delete(instanceId);
|
|
458
|
+
const { id } = app;
|
|
459
|
+
const appConfig = this.#microFEConfig.getConfigById(id);
|
|
460
|
+
const { hostUrl } = appConfig;
|
|
213
461
|
try {
|
|
214
|
-
|
|
462
|
+
this.#clearSession(app);
|
|
463
|
+
await this.#unmountApp({ id, instanceId });
|
|
215
464
|
} finally {
|
|
216
|
-
const frameEle = Frame.get(
|
|
217
|
-
if (
|
|
218
|
-
|
|
465
|
+
const frameEle = Frame.get(instanceId);
|
|
466
|
+
if (frameEle?.contentDocument) {
|
|
467
|
+
this.#unloadApp({
|
|
468
|
+
id,
|
|
469
|
+
instanceId,
|
|
470
|
+
hostUrl,
|
|
471
|
+
documentEle: frameEle.contentDocument
|
|
472
|
+
});
|
|
219
473
|
}
|
|
220
|
-
|
|
221
|
-
this.#soManager.removeAllScriptingObjects(id);
|
|
222
|
-
Frame.remove(id);
|
|
474
|
+
Frame.remove(instanceId);
|
|
223
475
|
}
|
|
224
476
|
};
|
|
225
477
|
/**
|
|
226
478
|
* dispatch event to guest microfrontend application
|
|
227
|
-
* @param {DispatchEventParams<EventId, Params>} params - event parameters
|
|
479
|
+
* @param {DispatchEventParams<EventId, Params, Options>} params - event parameters
|
|
228
480
|
*/
|
|
229
|
-
dispatchEvent = async (params) =>
|
|
481
|
+
dispatchEvent = async (params) => {
|
|
482
|
+
const {
|
|
483
|
+
event: { id, name }
|
|
484
|
+
} = params;
|
|
485
|
+
if (!id) throw new Error("Event Id is required");
|
|
486
|
+
const objectId = id.split(".")?.[0];
|
|
487
|
+
const scriptingObject = this.#soManager.getObject(objectId);
|
|
488
|
+
if (!scriptingObject) {
|
|
489
|
+
this.#logger.warn(
|
|
490
|
+
`Attempt to dispatch event ${name} on unknown object ${objectId}`
|
|
491
|
+
);
|
|
492
|
+
return Promise.resolve();
|
|
493
|
+
}
|
|
494
|
+
return this.#eventManager.dispatchEvent(scriptingObject, params);
|
|
495
|
+
};
|
|
230
496
|
/**
|
|
231
|
-
* Get
|
|
497
|
+
* Get App by instanceId
|
|
232
498
|
* @param id unique id of guest
|
|
499
|
+
* @param instanceId
|
|
233
500
|
* @returns guest instance
|
|
234
501
|
*/
|
|
235
|
-
|
|
502
|
+
getApp = (instanceId) => this.#activeApps.get(instanceId)?.guest;
|
|
236
503
|
/**
|
|
237
|
-
* Get list of active
|
|
504
|
+
* Get list of active apps
|
|
238
505
|
* @returns list of active guests
|
|
239
506
|
*/
|
|
240
|
-
|
|
507
|
+
getApps = () => [...this.#activeApps.values()].map((app) => app.guest);
|
|
241
508
|
/**
|
|
242
509
|
* Initialize appBridge
|
|
243
510
|
*/
|
|
@@ -250,87 +517,115 @@ class CAppBridge {
|
|
|
250
517
|
};
|
|
251
518
|
/**
|
|
252
519
|
* Mount guest micro frontend application into DOM
|
|
253
|
-
* @param
|
|
254
|
-
* @throws Error if application with given id is not found in configuration
|
|
520
|
+
* @param instanceId unique instance id of guest micro frontend application
|
|
521
|
+
* @throws Error if application with given instance id is not found in configuration
|
|
255
522
|
*/
|
|
256
|
-
mountApp = async (
|
|
257
|
-
if (!
|
|
523
|
+
mountApp = async (instanceId) => {
|
|
524
|
+
if (!instanceId) throw new Error("instanceId is required");
|
|
525
|
+
const { id } = this.#activeApps.get(instanceId) || {};
|
|
526
|
+
if (!id) {
|
|
527
|
+
throw new Error(
|
|
528
|
+
`Application with instance id ${instanceId} is not found`
|
|
529
|
+
);
|
|
530
|
+
}
|
|
258
531
|
const appConfig = this.#microFEConfig.getConfigById(id);
|
|
259
532
|
if (!appConfig) {
|
|
260
533
|
throw new Error(`Application with id ${id} is not found`);
|
|
261
534
|
}
|
|
262
|
-
await this.#mountApp(appConfig);
|
|
535
|
+
await this.#mountApp({ ...appConfig, instanceId });
|
|
263
536
|
};
|
|
264
537
|
/**
|
|
265
538
|
* Open guest micro frontend application
|
|
266
539
|
* @param {OpenAppParams} params - options to open guest application
|
|
267
540
|
*/
|
|
268
541
|
openApp = async (params) => {
|
|
269
|
-
const { id, frameOptions, history, theme } = params;
|
|
542
|
+
const { id, frameOptions, history, theme, homeRoute, initialRoute } = params;
|
|
543
|
+
const instanceId = uuidv4();
|
|
270
544
|
const appConfig = this.#microFEConfig.getConfigById(id);
|
|
271
545
|
if (!appConfig) {
|
|
272
|
-
throw new Error(`Application
|
|
546
|
+
throw new Error(`Application ${id} is not found in app config`);
|
|
273
547
|
}
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
548
|
+
const frameEle = await Frame.create({
|
|
549
|
+
id,
|
|
550
|
+
instanceId,
|
|
551
|
+
manifestPath: appConfig.manifestPath,
|
|
552
|
+
hostUrl: appConfig.hostUrl,
|
|
553
|
+
options: {
|
|
554
|
+
title: appConfig.name,
|
|
555
|
+
...frameOptions
|
|
556
|
+
}
|
|
279
557
|
});
|
|
280
558
|
if (!frameEle?.contentDocument)
|
|
281
559
|
throw new Error("unable to create iframe for the microapp");
|
|
282
560
|
try {
|
|
561
|
+
this.#appRegistry.add({
|
|
562
|
+
id,
|
|
563
|
+
instanceId,
|
|
564
|
+
documentEle: frameEle.contentDocument
|
|
565
|
+
});
|
|
283
566
|
await this.#loadApp({
|
|
284
|
-
|
|
567
|
+
instanceId,
|
|
285
568
|
history,
|
|
286
569
|
theme,
|
|
287
|
-
documentEle: frameEle.contentDocument
|
|
570
|
+
documentEle: frameEle.contentDocument,
|
|
571
|
+
containerId: frameOptions?.containerId,
|
|
572
|
+
...appConfig,
|
|
573
|
+
homeRoute: homeRoute ?? appConfig.homeRoute,
|
|
574
|
+
initialRoute
|
|
288
575
|
});
|
|
289
|
-
await this.#mountApp(appConfig);
|
|
290
|
-
|
|
576
|
+
await this.#mountApp({ instanceId, ...appConfig });
|
|
577
|
+
this.#manageSession({ id, instanceId });
|
|
578
|
+
return instanceId;
|
|
291
579
|
} catch (err) {
|
|
292
580
|
this.#unloadApp({
|
|
293
581
|
id,
|
|
582
|
+
instanceId,
|
|
294
583
|
hostUrl: appConfig.hostUrl,
|
|
295
584
|
documentEle: frameEle.contentDocument
|
|
296
585
|
});
|
|
297
|
-
Frame.remove(
|
|
586
|
+
Frame.remove(instanceId);
|
|
298
587
|
throw err;
|
|
299
588
|
}
|
|
300
589
|
};
|
|
301
|
-
/**
|
|
302
|
-
* emit event to all subscribers (deprecated)
|
|
303
|
-
* @deprecated use dispatchEvent instead
|
|
304
|
-
* @param eventId unique id of the event. The format is [scripting object name].[event name]
|
|
305
|
-
* @param data data to be sent to the subscribers of the event
|
|
306
|
-
* @returns true if event is published successfully
|
|
307
|
-
*/
|
|
308
|
-
publish = (eventId, data) => publish(eventId, data);
|
|
309
590
|
/**
|
|
310
591
|
* remove all listeners
|
|
311
592
|
*/
|
|
312
|
-
|
|
593
|
+
removeAllEventSubscriptions = () => {
|
|
313
594
|
this.#eventManager.unsubscribeAll();
|
|
314
595
|
};
|
|
596
|
+
/**
|
|
597
|
+
* removes all scripting objects from host
|
|
598
|
+
* @param guestId unique id of the guest application
|
|
599
|
+
*/
|
|
600
|
+
removeAllScriptingObjects = (guestId) => {
|
|
601
|
+
this.#soManager.removeAllScriptingObjects(guestId);
|
|
602
|
+
};
|
|
315
603
|
/**
|
|
316
604
|
* removes scripting object from the host
|
|
317
605
|
* @param objectId unique id of the scripting object
|
|
606
|
+
* @param guestId
|
|
318
607
|
*/
|
|
319
|
-
removeScriptingObject = (objectId) => {
|
|
320
|
-
this.#soManager.removeScriptingObject(objectId);
|
|
608
|
+
removeScriptingObject = (objectId, guestId) => {
|
|
609
|
+
this.#soManager.removeScriptingObject(objectId, guestId);
|
|
321
610
|
};
|
|
322
611
|
/**
|
|
323
612
|
* Unmount guest micro frontend application from DOM
|
|
324
|
-
* @param
|
|
613
|
+
* @param instanceId unique instance id of guest micro frontend application
|
|
325
614
|
* @throws Error if application with given id is not found in configuration
|
|
326
615
|
*/
|
|
327
|
-
unmountApp = async (
|
|
328
|
-
if (!
|
|
616
|
+
unmountApp = async (instanceId) => {
|
|
617
|
+
if (!instanceId) throw new Error("instanceId is required");
|
|
618
|
+
const { id } = this.#activeApps.get(instanceId) || {};
|
|
619
|
+
if (!id) {
|
|
620
|
+
throw new Error(
|
|
621
|
+
`Application with instance id ${instanceId} is not found`
|
|
622
|
+
);
|
|
623
|
+
}
|
|
329
624
|
const appConfig = this.#microFEConfig.getConfigById(id);
|
|
330
625
|
if (!appConfig) {
|
|
331
626
|
throw new Error(`Application with id ${id} is not found`);
|
|
332
627
|
}
|
|
333
|
-
await this.#unmountApp(appConfig);
|
|
628
|
+
await this.#unmountApp({ ...appConfig, instanceId });
|
|
334
629
|
};
|
|
335
630
|
}
|
|
336
631
|
export {
|