@elliemae/pui-app-sdk 5.15.0-beta.1 → 5.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/utils/auth/index.js +2 -2
- package/dist/cjs/utils/log-records.js +10 -10
- package/dist/cjs/utils/micro-frontend/guest.js +66 -9
- package/dist/cjs/view/micro-app/app-factory/index.js +120 -38
- package/dist/cjs/view/micro-app/index.js +2 -1
- package/dist/cjs/view/micro-app/use-app-will-render.js +12 -10
- package/dist/cjs/view/micro-iframe-app/app.js +2 -1
- package/dist/cjs/view/micro-iframe-app/index.js +2 -0
- package/dist/esm/utils/auth/index.js +2 -2
- package/dist/esm/utils/log-records.js +10 -10
- package/dist/esm/utils/micro-frontend/guest.js +66 -9
- package/dist/esm/view/micro-app/app-factory/index.js +120 -38
- package/dist/esm/view/micro-app/index.js +3 -2
- package/dist/esm/view/micro-app/use-app-will-render.js +12 -10
- package/dist/esm/view/micro-iframe-app/app.js +2 -1
- package/dist/esm/view/micro-iframe-app/index.js +3 -1
- package/dist/types/lib/utils/log-records.d.ts +5 -5
- package/dist/types/lib/utils/micro-frontend/guest.d.ts +2 -0
- package/dist/types/lib/utils/window.d.ts +3 -1
- package/dist/types/lib/view/micro-app/app-factory/index.d.ts +8 -4
- package/dist/types/lib/view/micro-app/types.d.ts +1 -1
- package/dist/types/lib/view/micro-app/use-app-will-render.d.ts +2 -1
- package/dist/types/lib/view/micro-iframe-app/app.d.ts +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +38 -38
|
@@ -72,7 +72,7 @@ const endSession = async ({
|
|
|
72
72
|
redirectUri,
|
|
73
73
|
responseType,
|
|
74
74
|
scope,
|
|
75
|
-
code = "
|
|
75
|
+
code = "",
|
|
76
76
|
skipRevoke = false
|
|
77
77
|
}) => {
|
|
78
78
|
try {
|
|
@@ -91,7 +91,7 @@ const endSession = async ({
|
|
|
91
91
|
const params = {
|
|
92
92
|
client_id: clientId,
|
|
93
93
|
redirect_uri: redirectUri,
|
|
94
|
-
error_code: code,
|
|
94
|
+
...code && { error_code: code },
|
|
95
95
|
response_type: responseType,
|
|
96
96
|
scope
|
|
97
97
|
};
|
|
@@ -42,25 +42,25 @@ const logRecords = {
|
|
|
42
42
|
code: "appsdk05",
|
|
43
43
|
message: `Application load failed. unable to locate ${assetName} in the manifest`
|
|
44
44
|
}),
|
|
45
|
-
APP_INIT_FAILED: (appId, errMsg) => ({
|
|
45
|
+
APP_INIT_FAILED: (appId, instanceId, errMsg) => ({
|
|
46
46
|
code: "appsdk06",
|
|
47
|
-
message: `Application load failed. Unable to load one or more application resources for appId: ${appId}. ${errMsg}`
|
|
47
|
+
message: `Application load failed. Unable to load one or more application resources for appId: ${appId} and instanceId: ${instanceId}. ${errMsg}`
|
|
48
48
|
}),
|
|
49
|
-
APP_LOADING: (appId) => ({
|
|
49
|
+
APP_LOADING: (appId, instanceId) => ({
|
|
50
50
|
code: "appsdk07",
|
|
51
|
-
message: `Application ${appId} is loading...`
|
|
51
|
+
message: `Application ${appId} with instanceId ${instanceId} is loading...`
|
|
52
52
|
}),
|
|
53
|
-
APP_LOADING_COMPLETE: (appId) => ({
|
|
53
|
+
APP_LOADING_COMPLETE: (appId, instanceId) => ({
|
|
54
54
|
code: "appsdk08",
|
|
55
|
-
message: `Application ${appId} loaded`
|
|
55
|
+
message: `Application ${appId} loaded with instanceId ${instanceId}`
|
|
56
56
|
}),
|
|
57
|
-
APP_UNLOADING: (appId) => ({
|
|
57
|
+
APP_UNLOADING: (appId, instanceId) => ({
|
|
58
58
|
code: "appsdk09",
|
|
59
|
-
message: `Application ${appId} unloading...`
|
|
59
|
+
message: `Application ${appId} with instanceId ${instanceId} unloading...`
|
|
60
60
|
}),
|
|
61
|
-
APP_UNLOADING_COMPLETE: (appId) => ({
|
|
61
|
+
APP_UNLOADING_COMPLETE: (appId, instanceId) => ({
|
|
62
62
|
code: "appsdk10",
|
|
63
|
-
message: `Application ${appId} unloaded`
|
|
63
|
+
message: `Application ${appId} with instanceId ${instanceId} unloaded`
|
|
64
64
|
}),
|
|
65
65
|
SSF_HOST_OBJECT_NOT_FOUND: (name) => ({
|
|
66
66
|
code: "appsdk11",
|
|
@@ -32,6 +32,7 @@ __export(guest_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(guest_exports);
|
|
34
34
|
var import_lodash = __toESM(require("lodash"));
|
|
35
|
+
var import_uuid = require("uuid");
|
|
35
36
|
var import_pui_theme = require("@elliemae/pui-theme");
|
|
36
37
|
var import_window = require("../window.js");
|
|
37
38
|
var import_app_config = require("../app-config/index.js");
|
|
@@ -53,6 +54,10 @@ const isCrossDomain = () => {
|
|
|
53
54
|
}
|
|
54
55
|
};
|
|
55
56
|
class CMicroAppGuest {
|
|
57
|
+
/**
|
|
58
|
+
* unique microapp id
|
|
59
|
+
*/
|
|
60
|
+
#uuid;
|
|
56
61
|
static instance;
|
|
57
62
|
logger;
|
|
58
63
|
appId;
|
|
@@ -62,9 +67,12 @@ class CMicroAppGuest {
|
|
|
62
67
|
onMount;
|
|
63
68
|
onUnmount;
|
|
64
69
|
onGetRef;
|
|
70
|
+
// eslint-disable-next-line max-statements
|
|
65
71
|
constructor(params) {
|
|
66
72
|
this.containerId = "app-container";
|
|
73
|
+
window.emui.uuid = window.emui.uuid || (0, import_uuid.v4)();
|
|
67
74
|
this.appId = window.emui?.appId || (0, import_config.getAppConfigValue)("appId");
|
|
75
|
+
this.#uuid = window.emui.uuid;
|
|
68
76
|
this.props = {
|
|
69
77
|
host: null,
|
|
70
78
|
hostUrl: null,
|
|
@@ -82,15 +90,7 @@ class CMicroAppGuest {
|
|
|
82
90
|
this.getHost = this.getHost.bind(this);
|
|
83
91
|
this.getLogger = this.getLogger.bind(this);
|
|
84
92
|
this.getProps = this.getProps.bind(this);
|
|
85
|
-
|
|
86
|
-
if (browserWindow) {
|
|
87
|
-
browserWindow.emui = browserWindow.emui || {};
|
|
88
|
-
browserWindow.emui[this.appId] = browserWindow.emui[this.appId] || {};
|
|
89
|
-
browserWindow.emui[this.appId].init = this.init.bind(this);
|
|
90
|
-
browserWindow.emui[this.appId].mount = this.mount.bind(this);
|
|
91
|
-
browserWindow.emui[this.appId].unmount = this.unmount.bind(this);
|
|
92
|
-
browserWindow.emui[this.appId].getRef = this.getRef.bind(this);
|
|
93
|
-
}
|
|
93
|
+
this.#addAppToGlobalVariable();
|
|
94
94
|
}
|
|
95
95
|
static getInstance(params) {
|
|
96
96
|
if (!this.instance) {
|
|
@@ -113,6 +113,60 @@ class CMicroAppGuest {
|
|
|
113
113
|
getProps() {
|
|
114
114
|
return this.props;
|
|
115
115
|
}
|
|
116
|
+
/**
|
|
117
|
+
* add the microapp to the global variable in the parent window and current window
|
|
118
|
+
*/
|
|
119
|
+
#addAppToGlobalVariable() {
|
|
120
|
+
const browserWindow = (0, import_window.getWindow)();
|
|
121
|
+
if (!browserWindow) return;
|
|
122
|
+
browserWindow.emui = browserWindow.emui || {};
|
|
123
|
+
const app = {
|
|
124
|
+
uuid: this.#uuid,
|
|
125
|
+
init: this.init.bind(this),
|
|
126
|
+
mount: this.mount.bind(this),
|
|
127
|
+
unmount: this.unmount.bind(this),
|
|
128
|
+
getRef: this.getRef.bind(this),
|
|
129
|
+
navigate: this.navigate.bind(this)
|
|
130
|
+
};
|
|
131
|
+
if (browserWindow.emui[this.appId]) {
|
|
132
|
+
if (Array.isArray(browserWindow.emui[this.appId])) {
|
|
133
|
+
const existingApps = browserWindow.emui[this.appId];
|
|
134
|
+
const appIndex = existingApps.findIndex((a) => a.uuid === this.#uuid);
|
|
135
|
+
if (appIndex > -1) existingApps[appIndex] = app;
|
|
136
|
+
else existingApps.push(app);
|
|
137
|
+
} else if (browserWindow.emui[this.appId].uuid === this.#uuid) {
|
|
138
|
+
browserWindow.emui[this.appId] = app;
|
|
139
|
+
} else {
|
|
140
|
+
browserWindow.emui[this.appId] = [
|
|
141
|
+
browserWindow.emui[this.appId],
|
|
142
|
+
app
|
|
143
|
+
];
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
browserWindow.emui[this.appId] = app;
|
|
147
|
+
}
|
|
148
|
+
window.emui.app = app;
|
|
149
|
+
window.addEventListener("beforeunload", this.#onWindowUnload.bind(this));
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* remove the microapp from the global variable from the parent window and current window
|
|
153
|
+
*/
|
|
154
|
+
#onWindowUnload() {
|
|
155
|
+
const browserWindow = (0, import_window.getWindow)();
|
|
156
|
+
if (Array.isArray(browserWindow.emui[this.appId])) {
|
|
157
|
+
const existingApps = browserWindow.emui[this.appId];
|
|
158
|
+
const index = existingApps.findIndex((app) => app.uuid === this.#uuid);
|
|
159
|
+
if (index > -1) existingApps.splice(index, 1);
|
|
160
|
+
if (existingApps.length === 0) {
|
|
161
|
+
delete browserWindow.emui[this.appId];
|
|
162
|
+
}
|
|
163
|
+
} else {
|
|
164
|
+
delete browserWindow.emui[this.appId];
|
|
165
|
+
}
|
|
166
|
+
delete window.emui.app;
|
|
167
|
+
this.unmount({ containerId: this.containerId }).catch(() => {
|
|
168
|
+
});
|
|
169
|
+
}
|
|
116
170
|
getSessionStorageItem(key) {
|
|
117
171
|
let value = sessionStorage.getItem(key);
|
|
118
172
|
if (!value && this.props.host?.getItem) {
|
|
@@ -134,6 +188,9 @@ class CMicroAppGuest {
|
|
|
134
188
|
}
|
|
135
189
|
return host;
|
|
136
190
|
}
|
|
191
|
+
get uuid() {
|
|
192
|
+
return this.#uuid;
|
|
193
|
+
}
|
|
137
194
|
async init(options) {
|
|
138
195
|
this.props = import_lodash.default.merge(this.props, options);
|
|
139
196
|
this.props.history = options?.history || this.props.history;
|
|
@@ -37,8 +37,23 @@ const cssType = /\.css$/;
|
|
|
37
37
|
const isCss = (fileName) => cssType.test(fileName);
|
|
38
38
|
const activeApps = {};
|
|
39
39
|
const getPathName = (url) => url ? new URL(url).pathname : "";
|
|
40
|
+
const getAppNotFoundError = (id, uuid) => `Application ${id} with instance id ${uuid} is not found. Most probably the appId property of app.config.json is not set to ${id}`;
|
|
41
|
+
const getMicroAppGuestFromWindow = ({
|
|
42
|
+
id,
|
|
43
|
+
uuid
|
|
44
|
+
}) => {
|
|
45
|
+
let microAppGuest = null;
|
|
46
|
+
const guests = window.emui?.[id];
|
|
47
|
+
if (Array.isArray(guests)) {
|
|
48
|
+
microAppGuest = guests.find((guest) => guest.uuid === uuid) ?? null;
|
|
49
|
+
} else {
|
|
50
|
+
microAppGuest = guests;
|
|
51
|
+
}
|
|
52
|
+
return microAppGuest;
|
|
53
|
+
};
|
|
40
54
|
const initApplication = async ({
|
|
41
55
|
id,
|
|
56
|
+
uuid,
|
|
42
57
|
name,
|
|
43
58
|
hostUrl,
|
|
44
59
|
history,
|
|
@@ -46,18 +61,19 @@ const initApplication = async ({
|
|
|
46
61
|
manifestPath,
|
|
47
62
|
homeRoute
|
|
48
63
|
}) => {
|
|
49
|
-
const app =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
64
|
+
const app = getMicroAppGuestFromWindow({
|
|
65
|
+
id,
|
|
66
|
+
uuid
|
|
67
|
+
});
|
|
68
|
+
if (!app) throw new Error(getAppNotFoundError(id, uuid));
|
|
55
69
|
const { init } = app;
|
|
56
70
|
if (!init || typeof init !== "function")
|
|
57
71
|
throw new Error(
|
|
58
72
|
`Application ${name} with id ${id} doesn't expose init method.`
|
|
59
73
|
);
|
|
60
|
-
const prevState = await import_web_storage.persistentStorage.get(
|
|
74
|
+
const prevState = await import_web_storage.persistentStorage.get(
|
|
75
|
+
`state-${id}-${uuid}`
|
|
76
|
+
);
|
|
61
77
|
return init({
|
|
62
78
|
host: import_host.CMicroAppHost.getInstance(),
|
|
63
79
|
hostUrl,
|
|
@@ -70,8 +86,12 @@ const initApplication = async ({
|
|
|
70
86
|
hostViewportSize: (0, import_window.getViewportSize)()
|
|
71
87
|
});
|
|
72
88
|
};
|
|
73
|
-
const mountApp = async ({ id, name }) => {
|
|
74
|
-
const app = (
|
|
89
|
+
const mountApp = async ({ id, uuid, name }) => {
|
|
90
|
+
const app = getMicroAppGuestFromWindow({
|
|
91
|
+
id,
|
|
92
|
+
uuid
|
|
93
|
+
});
|
|
94
|
+
if (!app) throw new Error(getAppNotFoundError(id, uuid));
|
|
75
95
|
const { mount } = app;
|
|
76
96
|
if (!mount || typeof mount !== "function")
|
|
77
97
|
throw new Error(
|
|
@@ -83,8 +103,11 @@ const mountApp = async ({ id, name }) => {
|
|
|
83
103
|
hostViewportSize: (0, import_window.getViewportSize)()
|
|
84
104
|
});
|
|
85
105
|
};
|
|
86
|
-
const unmountApp = async ({ id, name }) => {
|
|
87
|
-
const app = (
|
|
106
|
+
const unmountApp = async ({ id, uuid, name }) => {
|
|
107
|
+
const app = getMicroAppGuestFromWindow({
|
|
108
|
+
id,
|
|
109
|
+
uuid
|
|
110
|
+
});
|
|
88
111
|
if (!app) return null;
|
|
89
112
|
const { unmount } = app;
|
|
90
113
|
if (!unmount) return null;
|
|
@@ -96,64 +119,123 @@ const unmountApp = async ({ id, name }) => {
|
|
|
96
119
|
containerId: `${import_const.APP_CONTAINER_ID_PREFIX}${id}`
|
|
97
120
|
});
|
|
98
121
|
if (currentState) {
|
|
99
|
-
await import_web_storage.persistentStorage.set(`state-${id}`, currentState);
|
|
122
|
+
await import_web_storage.persistentStorage.set(`state-${id}-${uuid}`, currentState);
|
|
100
123
|
}
|
|
101
124
|
return Promise.resolve();
|
|
102
125
|
};
|
|
103
|
-
const addAppToActiveAppList = (id, elementIds) => {
|
|
104
|
-
const app = (
|
|
126
|
+
const addAppToActiveAppList = (id, uuid, elementIds) => {
|
|
127
|
+
const app = getMicroAppGuestFromWindow({
|
|
128
|
+
id,
|
|
129
|
+
uuid
|
|
130
|
+
});
|
|
131
|
+
if (!app) throw new Error(getAppNotFoundError(id, uuid));
|
|
105
132
|
const { getRef } = app;
|
|
106
|
-
activeApps[id] = { elementIds };
|
|
133
|
+
activeApps[`${id}-${uuid}`] = { elementIds };
|
|
107
134
|
const host = import_host.CMicroAppHost.getInstance();
|
|
108
|
-
if (host) host.activeGuests[id] = getRef && getRef() || {};
|
|
135
|
+
if (host) host.activeGuests[`${id}-${uuid}`] = getRef && getRef() || {};
|
|
109
136
|
return Promise.resolve();
|
|
110
137
|
};
|
|
111
138
|
const waitAndInitApplication = (appConfig, requests) => (
|
|
112
139
|
// wait for all assets to get downloaded
|
|
113
|
-
Promise.all(requests).then(addAppToActiveAppList.bind(null, appConfig.id)).then(initApplication.bind(null, appConfig)).catch((err) => {
|
|
114
|
-
const logRecord = import_log_records.logRecords.APP_INIT_FAILED(
|
|
140
|
+
Promise.all(requests).then(addAppToActiveAppList.bind(null, appConfig.id, appConfig.uuid)).then(initApplication.bind(null, appConfig)).catch((err) => {
|
|
141
|
+
const logRecord = import_log_records.logRecords.APP_INIT_FAILED(
|
|
142
|
+
appConfig.id,
|
|
143
|
+
appConfig.uuid,
|
|
144
|
+
err.message
|
|
145
|
+
);
|
|
115
146
|
(0, import_micro_frontend.getLogger)().error({ ...logRecord, exception: err });
|
|
116
147
|
throw new Error(logRecord.message);
|
|
117
148
|
})
|
|
118
149
|
);
|
|
119
|
-
const removeAssetsFromDOM = (id, documentEle = document) => {
|
|
150
|
+
const removeAssetsFromDOM = (id, uuid, documentEle = document) => {
|
|
120
151
|
const host = import_host.CMicroAppHost.getInstance();
|
|
121
|
-
if (host) delete host.activeGuests[id];
|
|
122
|
-
const { elementIds } = activeApps[id] || {};
|
|
152
|
+
if (host) delete host.activeGuests[`${id}-${uuid}`];
|
|
153
|
+
const { elementIds } = activeApps[`${id}-${uuid}`] || {};
|
|
123
154
|
if (elementIds) {
|
|
124
155
|
elementIds.forEach((elementId) => {
|
|
125
156
|
const ele = documentEle.getElementById(elementId);
|
|
126
157
|
if (ele) ele.remove();
|
|
127
158
|
});
|
|
128
|
-
delete activeApps[id];
|
|
159
|
+
delete activeApps[`${id}-${uuid}`];
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
const addAppToGlobalVariable = ({
|
|
163
|
+
id,
|
|
164
|
+
uuid,
|
|
165
|
+
documentEle
|
|
166
|
+
}) => {
|
|
167
|
+
const newAppInstance = {
|
|
168
|
+
uuid,
|
|
169
|
+
init: null,
|
|
170
|
+
mount: null,
|
|
171
|
+
unmount: null,
|
|
172
|
+
getRef: null,
|
|
173
|
+
navigate: null
|
|
174
|
+
};
|
|
175
|
+
const app = getMicroAppGuestFromWindow({ id, uuid });
|
|
176
|
+
if (app) {
|
|
177
|
+
if (!uuid) {
|
|
178
|
+
throw new Error(
|
|
179
|
+
`Application ${id} is already loaded. uuid is required to load multiple instances of the same app`
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
if (Array.isArray(window.emui[id])) {
|
|
183
|
+
window.emui[id].push(newAppInstance);
|
|
184
|
+
} else {
|
|
185
|
+
window.emui[id] = [window.emui[id], newAppInstance];
|
|
186
|
+
}
|
|
187
|
+
} else {
|
|
188
|
+
window.emui[id] = newAppInstance;
|
|
189
|
+
}
|
|
190
|
+
if (documentEle.defaultView) {
|
|
191
|
+
documentEle.defaultView.emui = documentEle.defaultView.emui ?? {};
|
|
192
|
+
documentEle.defaultView.emui.uuid = uuid;
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
const removeAppFromGlobalVariable = (id, uuid) => {
|
|
196
|
+
if (Array.isArray(window.emui[id])) {
|
|
197
|
+
const index = window.emui[id].findIndex(
|
|
198
|
+
(app) => app.uuid === uuid
|
|
199
|
+
);
|
|
200
|
+
if (index > -1) window.emui[id].splice(index, 1);
|
|
201
|
+
} else {
|
|
202
|
+
delete window.emui[id];
|
|
129
203
|
}
|
|
130
204
|
};
|
|
131
205
|
const loadApp = async (appConfig) => {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
206
|
+
const { id, uuid, documentEle } = appConfig;
|
|
207
|
+
addAppToGlobalVariable({ id, uuid, documentEle });
|
|
208
|
+
try {
|
|
209
|
+
(0, import_micro_frontend.getLogger)().info(import_log_records.logRecords.APP_LOADING(id, uuid));
|
|
210
|
+
let assets = appConfig.files;
|
|
211
|
+
const manifest = await (0, import_manifest.getAppManifest)(appConfig);
|
|
212
|
+
assets = (0, import_manifest.getFullFileNameofAssetsFromManifest)(manifest, appConfig.files);
|
|
213
|
+
let counter = 0;
|
|
214
|
+
const requests = assets.map((fileName) => {
|
|
215
|
+
counter += 1;
|
|
216
|
+
return !isCss(fileName) ? (0, import_script.addScriptToDOM)(appConfig, fileName, counter) : (0, import_style.addStylesToDOM)(appConfig, fileName, counter);
|
|
217
|
+
});
|
|
218
|
+
await waitAndInitApplication(appConfig, requests);
|
|
219
|
+
(0, import_micro_frontend.getLogger)().info(import_log_records.logRecords.APP_LOADING_COMPLETE(id, uuid));
|
|
220
|
+
} catch (err) {
|
|
221
|
+
removeAppFromGlobalVariable(id, uuid);
|
|
222
|
+
throw err;
|
|
223
|
+
}
|
|
143
224
|
};
|
|
144
225
|
const unloadApp = ({
|
|
145
226
|
id,
|
|
227
|
+
uuid,
|
|
146
228
|
hostUrl,
|
|
147
229
|
documentEle
|
|
148
230
|
}) => {
|
|
149
231
|
if (!hostUrl) throw new Error("Unable to unload app. hostUrl is required");
|
|
150
|
-
(0, import_micro_frontend.getLogger)().info(import_log_records.logRecords.APP_UNLOADING(id));
|
|
151
|
-
const app = (
|
|
232
|
+
(0, import_micro_frontend.getLogger)().info(import_log_records.logRecords.APP_UNLOADING(id, uuid));
|
|
233
|
+
const app = getMicroAppGuestFromWindow({ id, uuid });
|
|
152
234
|
if (!app) return;
|
|
153
|
-
removeAssetsFromDOM(id, documentEle);
|
|
235
|
+
removeAssetsFromDOM(id, uuid, documentEle);
|
|
154
236
|
(0, import_script.removeDynamicImportedScripts)(hostUrl, documentEle);
|
|
155
237
|
(0, import_script.removePrefetchLinks)(hostUrl, documentEle);
|
|
156
238
|
(0, import_style.removeDynamicImportedStyles)(hostUrl, documentEle);
|
|
157
|
-
|
|
158
|
-
(0, import_micro_frontend.getLogger)().info(import_log_records.logRecords.APP_UNLOADING_COMPLETE(id));
|
|
239
|
+
removeAppFromGlobalVariable(id, uuid);
|
|
240
|
+
(0, import_micro_frontend.getLogger)().info(import_log_records.logRecords.APP_UNLOADING_COMPLETE(id, uuid));
|
|
159
241
|
};
|
|
@@ -41,6 +41,7 @@ const Div = import_styled_components.default.div`
|
|
|
41
41
|
width: 100%;
|
|
42
42
|
`;
|
|
43
43
|
const MicroApp = (0, import_react.memo)((props) => {
|
|
44
|
-
(0,
|
|
44
|
+
const uuid = (0, import_react.useId)();
|
|
45
|
+
(0, import_use_app_will_render.useAppWillRender)({ uuid, ...props });
|
|
45
46
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Div, { id: `${import_const.APP_CONTAINER_ID_PREFIX}${props.id}` });
|
|
46
47
|
});
|
|
@@ -30,6 +30,7 @@ var import_micro_frontend = require("../../utils/micro-frontend/index.js");
|
|
|
30
30
|
var import_log_records = require("../../utils/log-records.js");
|
|
31
31
|
const useAppWillRender = ({
|
|
32
32
|
id,
|
|
33
|
+
uuid,
|
|
33
34
|
documentEle,
|
|
34
35
|
history,
|
|
35
36
|
theme,
|
|
@@ -45,27 +46,27 @@ const useAppWillRender = ({
|
|
|
45
46
|
[id]
|
|
46
47
|
);
|
|
47
48
|
const unload = (0, import_react.useCallback)(
|
|
48
|
-
async (
|
|
49
|
-
await (0, import_app_factory.unmountApp)(
|
|
50
|
-
(0, import_app_factory.unloadApp)(
|
|
49
|
+
async (appParams, loadFailed = false) => {
|
|
50
|
+
await (0, import_app_factory.unmountApp)(appParams);
|
|
51
|
+
(0, import_app_factory.unloadApp)(appParams);
|
|
51
52
|
if (!loadFailed && onUnloadComplete) onUnloadComplete();
|
|
52
53
|
},
|
|
53
54
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
54
55
|
[]
|
|
55
56
|
);
|
|
56
57
|
const load = (0, import_react.useCallback)(
|
|
57
|
-
async (
|
|
58
|
+
async (appParams) => {
|
|
58
59
|
if (dispatch) dispatch(import_actions.waitMessage.open());
|
|
59
60
|
try {
|
|
60
61
|
if (ref.current) await ref.current;
|
|
61
|
-
await (0, import_app_factory.loadApp)(
|
|
62
|
-
await (0, import_app_factory.mountApp)(
|
|
62
|
+
await (0, import_app_factory.loadApp)(appParams);
|
|
63
|
+
await (0, import_app_factory.mountApp)(appParams);
|
|
63
64
|
} catch (ex) {
|
|
64
65
|
(0, import_micro_frontend.getLogger)().error({
|
|
65
66
|
...import_log_records.logRecords.APP_CONFIG_LOAD_FAILED,
|
|
66
67
|
exception: ex
|
|
67
68
|
});
|
|
68
|
-
await unload(
|
|
69
|
+
await unload(appParams, true);
|
|
69
70
|
throw ex;
|
|
70
71
|
}
|
|
71
72
|
if (dispatch) dispatch(import_actions.waitMessage.close());
|
|
@@ -81,9 +82,10 @@ const useAppWillRender = ({
|
|
|
81
82
|
theme,
|
|
82
83
|
homeRoute
|
|
83
84
|
});
|
|
84
|
-
|
|
85
|
+
const appParams = { ...appConfig, uuid };
|
|
86
|
+
load(appParams);
|
|
85
87
|
return () => {
|
|
86
|
-
ref.current = unload(
|
|
88
|
+
ref.current = unload(appParams);
|
|
87
89
|
};
|
|
88
|
-
}, [documentEle, getConfig, history, theme, homeRoute, load, unload]);
|
|
90
|
+
}, [documentEle, getConfig, history, theme, homeRoute, load, unload, uuid]);
|
|
89
91
|
};
|
|
@@ -38,11 +38,12 @@ var import_iframe2 = require("./iframe/index.js");
|
|
|
38
38
|
var import_use_frame_loaded = require("./use-frame-loaded.js");
|
|
39
39
|
var import_use_app_will_render = require("../micro-app/use-app-will-render.js");
|
|
40
40
|
const App = (0, import_react.memo)(
|
|
41
|
-
({ id, dispose, onUnloadComplete, ...rest }) => {
|
|
41
|
+
({ id, uuid, dispose, onUnloadComplete, ...rest }) => {
|
|
42
42
|
const [documentEle, setDocumentEle] = (0, import_react.useState)(null);
|
|
43
43
|
(0, import_use_frame_loaded.useFrameLoaded)({ id, documentEle, ...rest });
|
|
44
44
|
(0, import_use_app_will_render.useAppWillRender)({
|
|
45
45
|
id,
|
|
46
|
+
uuid,
|
|
46
47
|
documentEle: dispose ? null : documentEle,
|
|
47
48
|
onUnloadComplete,
|
|
48
49
|
...rest
|
|
@@ -28,6 +28,7 @@ var import_app = require("./app.js");
|
|
|
28
28
|
const MicroIFrameApp = (0, import_react2.memo)(({ entityId = null, ...rest }) => {
|
|
29
29
|
const [disposePrevApp, setDisposePrevApp] = (0, import_react2.useState)(false);
|
|
30
30
|
const [appKey, setAppKey] = (0, import_react2.useState)(Date.now());
|
|
31
|
+
const uuid = (0, import_react2.useId)();
|
|
31
32
|
const prevEntityId = (0, import_use_previous.usePrevious)(entityId);
|
|
32
33
|
(0, import_react2.useEffect)(() => {
|
|
33
34
|
if (prevEntityId !== entityId && prevEntityId) {
|
|
@@ -38,6 +39,7 @@ const MicroIFrameApp = (0, import_react2.memo)(({ entityId = null, ...rest }) =>
|
|
|
38
39
|
import_app.App,
|
|
39
40
|
{
|
|
40
41
|
...rest,
|
|
42
|
+
uuid,
|
|
41
43
|
key: appKey,
|
|
42
44
|
dispose: disposePrevApp,
|
|
43
45
|
onUnloadComplete: () => {
|
|
@@ -48,7 +48,7 @@ const endSession = async ({
|
|
|
48
48
|
redirectUri,
|
|
49
49
|
responseType,
|
|
50
50
|
scope,
|
|
51
|
-
code = "
|
|
51
|
+
code = "",
|
|
52
52
|
skipRevoke = false
|
|
53
53
|
}) => {
|
|
54
54
|
try {
|
|
@@ -67,7 +67,7 @@ const endSession = async ({
|
|
|
67
67
|
const params = {
|
|
68
68
|
client_id: clientId,
|
|
69
69
|
redirect_uri: redirectUri,
|
|
70
|
-
error_code: code,
|
|
70
|
+
...code && { error_code: code },
|
|
71
71
|
response_type: responseType,
|
|
72
72
|
scope
|
|
73
73
|
};
|
|
@@ -19,25 +19,25 @@ const logRecords = {
|
|
|
19
19
|
code: "appsdk05",
|
|
20
20
|
message: `Application load failed. unable to locate ${assetName} in the manifest`
|
|
21
21
|
}),
|
|
22
|
-
APP_INIT_FAILED: (appId, errMsg) => ({
|
|
22
|
+
APP_INIT_FAILED: (appId, instanceId, errMsg) => ({
|
|
23
23
|
code: "appsdk06",
|
|
24
|
-
message: `Application load failed. Unable to load one or more application resources for appId: ${appId}. ${errMsg}`
|
|
24
|
+
message: `Application load failed. Unable to load one or more application resources for appId: ${appId} and instanceId: ${instanceId}. ${errMsg}`
|
|
25
25
|
}),
|
|
26
|
-
APP_LOADING: (appId) => ({
|
|
26
|
+
APP_LOADING: (appId, instanceId) => ({
|
|
27
27
|
code: "appsdk07",
|
|
28
|
-
message: `Application ${appId} is loading...`
|
|
28
|
+
message: `Application ${appId} with instanceId ${instanceId} is loading...`
|
|
29
29
|
}),
|
|
30
|
-
APP_LOADING_COMPLETE: (appId) => ({
|
|
30
|
+
APP_LOADING_COMPLETE: (appId, instanceId) => ({
|
|
31
31
|
code: "appsdk08",
|
|
32
|
-
message: `Application ${appId} loaded`
|
|
32
|
+
message: `Application ${appId} loaded with instanceId ${instanceId}`
|
|
33
33
|
}),
|
|
34
|
-
APP_UNLOADING: (appId) => ({
|
|
34
|
+
APP_UNLOADING: (appId, instanceId) => ({
|
|
35
35
|
code: "appsdk09",
|
|
36
|
-
message: `Application ${appId} unloading...`
|
|
36
|
+
message: `Application ${appId} with instanceId ${instanceId} unloading...`
|
|
37
37
|
}),
|
|
38
|
-
APP_UNLOADING_COMPLETE: (appId) => ({
|
|
38
|
+
APP_UNLOADING_COMPLETE: (appId, instanceId) => ({
|
|
39
39
|
code: "appsdk10",
|
|
40
|
-
message: `Application ${appId} unloaded`
|
|
40
|
+
message: `Application ${appId} with instanceId ${instanceId} unloaded`
|
|
41
41
|
}),
|
|
42
42
|
SSF_HOST_OBJECT_NOT_FOUND: (name) => ({
|
|
43
43
|
code: "appsdk11",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import _ from "lodash";
|
|
2
|
+
import { v4 as uuidv4 } from "uuid";
|
|
2
3
|
import { getDefaultTheme } from "@elliemae/pui-theme";
|
|
3
4
|
import { getWindow } from "../window.js";
|
|
4
5
|
import { loadAppConfig } from "../app-config/index.js";
|
|
@@ -20,6 +21,10 @@ const isCrossDomain = () => {
|
|
|
20
21
|
}
|
|
21
22
|
};
|
|
22
23
|
class CMicroAppGuest {
|
|
24
|
+
/**
|
|
25
|
+
* unique microapp id
|
|
26
|
+
*/
|
|
27
|
+
#uuid;
|
|
23
28
|
static instance;
|
|
24
29
|
logger;
|
|
25
30
|
appId;
|
|
@@ -29,9 +34,12 @@ class CMicroAppGuest {
|
|
|
29
34
|
onMount;
|
|
30
35
|
onUnmount;
|
|
31
36
|
onGetRef;
|
|
37
|
+
// eslint-disable-next-line max-statements
|
|
32
38
|
constructor(params) {
|
|
33
39
|
this.containerId = "app-container";
|
|
40
|
+
window.emui.uuid = window.emui.uuid || uuidv4();
|
|
34
41
|
this.appId = window.emui?.appId || getAppConfigValue("appId");
|
|
42
|
+
this.#uuid = window.emui.uuid;
|
|
35
43
|
this.props = {
|
|
36
44
|
host: null,
|
|
37
45
|
hostUrl: null,
|
|
@@ -49,15 +57,7 @@ class CMicroAppGuest {
|
|
|
49
57
|
this.getHost = this.getHost.bind(this);
|
|
50
58
|
this.getLogger = this.getLogger.bind(this);
|
|
51
59
|
this.getProps = this.getProps.bind(this);
|
|
52
|
-
|
|
53
|
-
if (browserWindow) {
|
|
54
|
-
browserWindow.emui = browserWindow.emui || {};
|
|
55
|
-
browserWindow.emui[this.appId] = browserWindow.emui[this.appId] || {};
|
|
56
|
-
browserWindow.emui[this.appId].init = this.init.bind(this);
|
|
57
|
-
browserWindow.emui[this.appId].mount = this.mount.bind(this);
|
|
58
|
-
browserWindow.emui[this.appId].unmount = this.unmount.bind(this);
|
|
59
|
-
browserWindow.emui[this.appId].getRef = this.getRef.bind(this);
|
|
60
|
-
}
|
|
60
|
+
this.#addAppToGlobalVariable();
|
|
61
61
|
}
|
|
62
62
|
static getInstance(params) {
|
|
63
63
|
if (!this.instance) {
|
|
@@ -80,6 +80,60 @@ class CMicroAppGuest {
|
|
|
80
80
|
getProps() {
|
|
81
81
|
return this.props;
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* add the microapp to the global variable in the parent window and current window
|
|
85
|
+
*/
|
|
86
|
+
#addAppToGlobalVariable() {
|
|
87
|
+
const browserWindow = getWindow();
|
|
88
|
+
if (!browserWindow) return;
|
|
89
|
+
browserWindow.emui = browserWindow.emui || {};
|
|
90
|
+
const app = {
|
|
91
|
+
uuid: this.#uuid,
|
|
92
|
+
init: this.init.bind(this),
|
|
93
|
+
mount: this.mount.bind(this),
|
|
94
|
+
unmount: this.unmount.bind(this),
|
|
95
|
+
getRef: this.getRef.bind(this),
|
|
96
|
+
navigate: this.navigate.bind(this)
|
|
97
|
+
};
|
|
98
|
+
if (browserWindow.emui[this.appId]) {
|
|
99
|
+
if (Array.isArray(browserWindow.emui[this.appId])) {
|
|
100
|
+
const existingApps = browserWindow.emui[this.appId];
|
|
101
|
+
const appIndex = existingApps.findIndex((a) => a.uuid === this.#uuid);
|
|
102
|
+
if (appIndex > -1) existingApps[appIndex] = app;
|
|
103
|
+
else existingApps.push(app);
|
|
104
|
+
} else if (browserWindow.emui[this.appId].uuid === this.#uuid) {
|
|
105
|
+
browserWindow.emui[this.appId] = app;
|
|
106
|
+
} else {
|
|
107
|
+
browserWindow.emui[this.appId] = [
|
|
108
|
+
browserWindow.emui[this.appId],
|
|
109
|
+
app
|
|
110
|
+
];
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
browserWindow.emui[this.appId] = app;
|
|
114
|
+
}
|
|
115
|
+
window.emui.app = app;
|
|
116
|
+
window.addEventListener("beforeunload", this.#onWindowUnload.bind(this));
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* remove the microapp from the global variable from the parent window and current window
|
|
120
|
+
*/
|
|
121
|
+
#onWindowUnload() {
|
|
122
|
+
const browserWindow = getWindow();
|
|
123
|
+
if (Array.isArray(browserWindow.emui[this.appId])) {
|
|
124
|
+
const existingApps = browserWindow.emui[this.appId];
|
|
125
|
+
const index = existingApps.findIndex((app) => app.uuid === this.#uuid);
|
|
126
|
+
if (index > -1) existingApps.splice(index, 1);
|
|
127
|
+
if (existingApps.length === 0) {
|
|
128
|
+
delete browserWindow.emui[this.appId];
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
delete browserWindow.emui[this.appId];
|
|
132
|
+
}
|
|
133
|
+
delete window.emui.app;
|
|
134
|
+
this.unmount({ containerId: this.containerId }).catch(() => {
|
|
135
|
+
});
|
|
136
|
+
}
|
|
83
137
|
getSessionStorageItem(key) {
|
|
84
138
|
let value = sessionStorage.getItem(key);
|
|
85
139
|
if (!value && this.props.host?.getItem) {
|
|
@@ -101,6 +155,9 @@ class CMicroAppGuest {
|
|
|
101
155
|
}
|
|
102
156
|
return host;
|
|
103
157
|
}
|
|
158
|
+
get uuid() {
|
|
159
|
+
return this.#uuid;
|
|
160
|
+
}
|
|
104
161
|
async init(options) {
|
|
105
162
|
this.props = _.merge(this.props, options);
|
|
106
163
|
this.props.history = options?.history || this.props.history;
|