@elliemae/pui-app-bridge 2.21.4 → 2.23.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.
Files changed (103) hide show
  1. package/dist/cjs/appBridge.js +68 -69
  2. package/dist/cjs/appRegistry.js +16 -10
  3. package/dist/cjs/config/app.js +21 -9
  4. package/dist/cjs/config/microFE.js +9 -8
  5. package/dist/cjs/eventManager.js +30 -23
  6. package/dist/cjs/frame.js +79 -47
  7. package/dist/cjs/index.html +1 -1
  8. package/dist/cjs/index.js +8 -1
  9. package/dist/cjs/loaders/manifest.js +9 -2
  10. package/dist/cjs/loaders/script.js +165 -12
  11. package/dist/cjs/loaders/style.js +100 -10
  12. package/dist/cjs/microfeHost.js +6 -5
  13. package/dist/cjs/utils.js +3 -29
  14. package/dist/esm/appBridge.js +57 -68
  15. package/dist/esm/appRegistry.js +16 -10
  16. package/dist/esm/config/app.js +21 -9
  17. package/dist/esm/config/microFE.js +9 -8
  18. package/dist/esm/eventManager.js +30 -23
  19. package/dist/esm/frame.js +79 -47
  20. package/dist/esm/index.html +1 -1
  21. package/dist/esm/index.js +8 -1
  22. package/dist/esm/loaders/manifest.js +9 -2
  23. package/dist/esm/loaders/script.js +166 -13
  24. package/dist/esm/loaders/style.js +101 -11
  25. package/dist/esm/microfeHost.js +6 -5
  26. package/dist/esm/utils.js +3 -29
  27. package/dist/public/creditService/latest/creditService.checksum.js +1 -1
  28. package/dist/public/creditService/latest/creditService.checksum.js.br +0 -0
  29. package/dist/public/creditService/latest/creditService.checksum.js.gz +0 -0
  30. package/dist/public/creditService/latest/creditService.checksum.js.map +1 -1
  31. package/dist/public/frame.html +1 -1
  32. package/dist/public/guest/businessObjects.js.map +1 -1
  33. package/dist/public/guest/util.js.map +1 -1
  34. package/dist/public/index.html +1 -1
  35. package/dist/public/init.js +1 -1
  36. package/dist/public/init.js.br +0 -0
  37. package/dist/public/init.js.gz +0 -0
  38. package/dist/public/init.js.map +1 -1
  39. package/dist/public/js/emuiAppBridge.24ac0c1126377d1fd21f.js +25 -0
  40. package/dist/public/js/emuiAppBridge.24ac0c1126377d1fd21f.js.br +0 -0
  41. package/dist/public/js/emuiAppBridge.24ac0c1126377d1fd21f.js.gz +0 -0
  42. package/dist/public/js/emuiAppBridge.24ac0c1126377d1fd21f.js.map +1 -0
  43. package/dist/public/latest/app.config.json +6 -6
  44. package/dist/public/loan-object.js.map +1 -1
  45. package/dist/public/loanValidation/latest/loanValidation.checksum.js +1 -1
  46. package/dist/public/loanValidation/latest/loanValidation.checksum.js.br +0 -0
  47. package/dist/public/loanValidation/latest/loanValidation.checksum.js.gz +0 -0
  48. package/dist/public/loanValidation/latest/loanValidation.checksum.js.map +1 -1
  49. package/dist/public/pricingService/latest/pricingService.checksum.js +2 -2
  50. package/dist/public/pricingService/latest/pricingService.checksum.js.br +0 -0
  51. package/dist/public/pricingService/latest/pricingService.checksum.js.gz +0 -0
  52. package/dist/public/pricingService/latest/pricingService.checksum.js.map +1 -1
  53. package/dist/public/utils.js +1 -1
  54. package/dist/public/utils.js.br +0 -0
  55. package/dist/public/utils.js.gz +0 -0
  56. package/dist/public/utils.js.map +1 -1
  57. package/dist/types/lib/appBridge.d.ts +1 -1
  58. package/dist/types/lib/appRegistry.d.ts +4 -4
  59. package/dist/types/lib/config/app.d.ts +3 -4
  60. package/dist/types/lib/eventManager.d.ts +3 -1
  61. package/dist/types/lib/frame.d.ts +0 -10
  62. package/dist/types/lib/index.d.ts +3 -0
  63. package/dist/types/lib/loaders/manifest.d.ts +1 -0
  64. package/dist/types/lib/loaders/script.d.ts +99 -5
  65. package/dist/types/lib/loaders/style.d.ts +77 -4
  66. package/dist/types/lib/microfeHost.d.ts +1 -1
  67. package/dist/types/lib/tests/loaders/script.test.d.ts +1 -0
  68. package/dist/types/lib/utils.d.ts +1 -6
  69. package/dist/types/tsconfig.tsbuildinfo +1 -1
  70. package/dist/umd/creditService/latest/creditService.checksum.js +1 -1
  71. package/dist/umd/creditService/latest/creditService.checksum.js.br +0 -0
  72. package/dist/umd/creditService/latest/creditService.checksum.js.gz +0 -0
  73. package/dist/umd/creditService/latest/creditService.checksum.js.map +1 -1
  74. package/dist/umd/guest/businessObjects.js.map +1 -1
  75. package/dist/umd/guest/util.js.map +1 -1
  76. package/dist/umd/index.html +1 -1
  77. package/dist/umd/index.js +9 -35
  78. package/dist/umd/index.js.br +0 -0
  79. package/dist/umd/index.js.gz +0 -0
  80. package/dist/umd/index.js.map +1 -1
  81. package/dist/umd/init.js +1 -1
  82. package/dist/umd/init.js.br +0 -0
  83. package/dist/umd/init.js.gz +0 -0
  84. package/dist/umd/init.js.map +1 -1
  85. package/dist/umd/latest/app.config.json +6 -6
  86. package/dist/umd/loan-object.js.map +1 -1
  87. package/dist/umd/loanValidation/latest/loanValidation.checksum.js +1 -1
  88. package/dist/umd/loanValidation/latest/loanValidation.checksum.js.br +0 -0
  89. package/dist/umd/loanValidation/latest/loanValidation.checksum.js.gz +0 -0
  90. package/dist/umd/loanValidation/latest/loanValidation.checksum.js.map +1 -1
  91. package/dist/umd/pricingService/latest/pricingService.checksum.js +2 -2
  92. package/dist/umd/pricingService/latest/pricingService.checksum.js.br +0 -0
  93. package/dist/umd/pricingService/latest/pricingService.checksum.js.gz +0 -0
  94. package/dist/umd/pricingService/latest/pricingService.checksum.js.map +1 -1
  95. package/dist/umd/utils.js +1 -1
  96. package/dist/umd/utils.js.br +0 -0
  97. package/dist/umd/utils.js.gz +0 -0
  98. package/dist/umd/utils.js.map +1 -1
  99. package/package.json +25 -26
  100. package/dist/public/js/emuiAppBridge.4c0a4243086e44e29d0b.js +0 -51
  101. package/dist/public/js/emuiAppBridge.4c0a4243086e44e29d0b.js.br +0 -0
  102. package/dist/public/js/emuiAppBridge.4c0a4243086e44e29d0b.js.gz +0 -0
  103. package/dist/public/js/emuiAppBridge.4c0a4243086e44e29d0b.js.map +0 -1
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
+ var __create = Object.create;
2
3
  var __defProp = Object.defineProperty;
3
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
5
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
8
  var __export = (target, all) => {
7
9
  for (var name in all)
@@ -15,13 +17,21 @@ var __copyProps = (to, from, except, desc) => {
15
17
  }
16
18
  return to;
17
19
  };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
18
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
29
  var appBridge_exports = {};
20
30
  __export(appBridge_exports, {
21
31
  CAppBridge: () => CAppBridge
22
32
  });
23
33
  module.exports = __toCommonJS(appBridge_exports);
24
- var import_lodash = require("lodash");
34
+ var import_throttle = __toESM(require("lodash/throttle"), 1);
25
35
  var import_uuid = require("uuid");
26
36
  var import_pui_scripting_object = require("@elliemae/pui-scripting-object");
27
37
  var import_microfe_common = require("@elliemae/microfe-common");
@@ -99,7 +109,7 @@ class CAppBridge {
99
109
  this.#scriptLoader = new import_loaders.ScriptLoader(logger);
100
110
  this.#styleLoader = new import_loaders.StyleLoader(logger);
101
111
  this.#soManager = new import_microfe_common.ScriptingObjectManager();
102
- this.#eventManager = new import_eventManager.EventManager();
112
+ this.#eventManager = new import_eventManager.EventManager(this.#logger);
103
113
  }
104
114
  #isFunction(value) {
105
115
  return typeof value === "function";
@@ -144,12 +154,14 @@ class CAppBridge {
144
154
  * @param param0.instanceId
145
155
  * @param elementIds
146
156
  * @param param0.documentEle
157
+ * @param param0.elementIds
147
158
  */
148
159
  #addAppToActiveAppList = ({
149
160
  id,
150
161
  instanceId,
151
- documentEle
152
- }, elementIds) => {
162
+ documentEle,
163
+ elementIds
164
+ }) => {
153
165
  const app = this.#appRegistry.get({ id, instanceId });
154
166
  if (!app) {
155
167
  throw new Error(this.#getAppNotFoundError(id, instanceId));
@@ -164,45 +176,6 @@ class CAppBridge {
164
176
  }
165
177
  });
166
178
  };
167
- #waitAndInitApplication = (options, requests) => {
168
- const {
169
- id,
170
- instanceId,
171
- containerId,
172
- name,
173
- hostUrl,
174
- manifestPath,
175
- homeRoute,
176
- initialRoute,
177
- history,
178
- theme,
179
- documentEle
180
- } = options;
181
- return Promise.all(requests).then(
182
- this.#addAppToActiveAppList.bind(null, { id, instanceId, documentEle })
183
- ).then(
184
- this.#initApplication.bind(null, {
185
- id,
186
- instanceId,
187
- containerId,
188
- name,
189
- hostUrl,
190
- manifestPath,
191
- homeRoute,
192
- initialRoute,
193
- history,
194
- theme
195
- })
196
- ).catch((err) => {
197
- const message = `Application load failed. Unable to load one or more resources for ${options.id} with instance id ${instanceId}. ${err.message}`;
198
- this.#logger.error({
199
- message,
200
- appId: id,
201
- exception: err
202
- });
203
- throw new Error(message);
204
- });
205
- };
206
179
  #initApplication = async ({
207
180
  id,
208
181
  instanceId,
@@ -249,30 +222,45 @@ class CAppBridge {
249
222
  });
250
223
  };
251
224
  #loadApp = async (options) => {
252
- const { id, instanceId, files, name, hostUrl, documentEle, isJsModule } = options;
253
- this.#logger.debug(
254
- `Application ${id} with instance id ${instanceId} is loading...`
255
- );
256
- let assets = files;
257
- const manifest = await import_loaders.ManifestLoader.get(options);
258
- assets = import_loaders.ManifestLoader.getFullFileNameofAssets(manifest, files);
259
- let counter = 0;
260
- const requests = assets.map((fileName) => {
261
- counter += 1;
262
- const resourceOptions = {
225
+ try {
226
+ const { id, instanceId, files, name, hostUrl, documentEle, isJsModule } = options;
227
+ this.#logger.debug(
228
+ `Application ${id} with instance id ${instanceId} is loading...`
229
+ );
230
+ let assets = files;
231
+ const manifest = await import_loaders.ManifestLoader.get(options);
232
+ assets = import_loaders.ManifestLoader.getFullFileNameofAssets(manifest, files);
233
+ const cssAssets = assets.filter((fileName) => isCss(fileName));
234
+ const jsAssets = assets.filter((fileName) => !isCss(fileName));
235
+ const loadOptions = {
263
236
  name,
264
237
  hostUrl,
265
238
  documentEle,
266
- fileName,
267
- index: counter,
268
- isJsModule
239
+ isESMModule: isJsModule
269
240
  };
270
- return !isCss(fileName) ? this.#scriptLoader.add(resourceOptions) : this.#styleLoader.add(resourceOptions);
271
- });
272
- await this.#waitAndInitApplication(options, requests);
273
- this.#logger.audit(
274
- `Application ${id} with instance id ${instanceId} loaded`
275
- );
241
+ const [styleElementIds, scriptElementIds] = await Promise.all([
242
+ this.#styleLoader.load(cssAssets, loadOptions),
243
+ this.#scriptLoader.load(jsAssets, loadOptions)
244
+ ]);
245
+ this.#addAppToActiveAppList({
246
+ id,
247
+ instanceId,
248
+ documentEle,
249
+ elementIds: [...styleElementIds, ...scriptElementIds]
250
+ });
251
+ await this.#initApplication(options);
252
+ this.#logger.audit(
253
+ `Application ${id} with instance id ${instanceId} loaded`
254
+ );
255
+ } catch (err) {
256
+ const message = `Application load failed. Unable to load one or more resources for ${options.id} with instance id ${options.instanceId}. ${err.message}`;
257
+ this.#logger.error({
258
+ message,
259
+ appId: options.id,
260
+ exception: err
261
+ });
262
+ throw new Error(message);
263
+ }
276
264
  };
277
265
  #unloadApp = ({ id, instanceId, hostUrl, documentEle }) => {
278
266
  this.#logger.debug(
@@ -335,7 +323,7 @@ class CAppBridge {
335
323
  }
336
324
  const app = this.#activeApps.get(instanceId);
337
325
  if (!app) return;
338
- app.keepAlive = (0, import_lodash.throttle)(
326
+ app.keepAlive = (0, import_throttle.default)(
339
327
  async () => {
340
328
  try {
341
329
  await appObj.keepSessionAlive();
@@ -367,11 +355,15 @@ class CAppBridge {
367
355
  */
368
356
  #clearSession = (app) => {
369
357
  if (!this.#extendSession || !app) return;
370
- const { keepAlive } = app;
358
+ const { keepAlive, instanceId } = app;
371
359
  if (keepAlive) {
372
- userInteractionEvents.forEach((eventType) => {
373
- document.removeEventListener(eventType, keepAlive);
374
- });
360
+ const frameEle = import_frame.Frame.get(instanceId);
361
+ const targetDoc = frameEle?.contentDocument;
362
+ if (targetDoc) {
363
+ userInteractionEvents.forEach((eventType) => {
364
+ targetDoc.removeEventListener(eventType, keepAlive);
365
+ });
366
+ }
375
367
  app.keepAlive?.cancel();
376
368
  }
377
369
  };
@@ -460,6 +452,7 @@ class CAppBridge {
460
452
  * Close guest micro frontend application
461
453
  * @param instanceId unique instance id of the application
462
454
  */
455
+ // eslint-disable-next-line max-statements
463
456
  closeApp = async (instanceId) => {
464
457
  if (!instanceId) throw new Error("instanceId is required");
465
458
  const app = this.#activeApps.get(instanceId);
@@ -469,9 +462,14 @@ class CAppBridge {
469
462
  );
470
463
  return;
471
464
  }
472
- this.#activeApps.delete(instanceId);
473
465
  const { id } = app;
474
466
  const appConfig = this.#microFEConfig.getConfigById(id);
467
+ if (!appConfig) {
468
+ this.#logger.warn(`Configuration for application ${id} is not found`);
469
+ this.#activeApps.delete(instanceId);
470
+ import_frame.Frame.remove(instanceId);
471
+ return;
472
+ }
475
473
  const { hostUrl } = appConfig;
476
474
  try {
477
475
  this.#clearSession(app);
@@ -486,6 +484,7 @@ class CAppBridge {
486
484
  documentEle: frameEle.contentDocument
487
485
  });
488
486
  }
487
+ this.#activeApps.delete(instanceId);
489
488
  import_frame.Frame.remove(instanceId);
490
489
  }
491
490
  };
@@ -34,7 +34,12 @@ class CAppRegistry {
34
34
  * @param param0.appId
35
35
  * @param param0.app
36
36
  */
37
+ // eslint-disable-next-line complexity
37
38
  #registerApp = ({ appId, app }) => {
39
+ if (!appId) throw new Error("appId is required");
40
+ if (appId === "__proto__" || appId === "constructor" || appId === "prototype") {
41
+ throw new Error(`Invalid appId: ${appId}`);
42
+ }
38
43
  if (!app?.uuid) throw new Error("application uuid is required");
39
44
  window.emui[appId] = window.emui[appId] || [];
40
45
  if (Array.isArray(window.emui[appId])) {
@@ -51,7 +56,7 @@ class CAppRegistry {
51
56
  if (existingApp?.uuid === app.uuid) {
52
57
  existingApp = { ...existingApp, ...app };
53
58
  window.emui[appId] = [existingApp];
54
- } else if (typeof existingApp.init === void 0) {
59
+ } else if (typeof existingApp.init === "undefined") {
55
60
  window.emui[appId] = [{ ...existingApp, ...app }];
56
61
  } else {
57
62
  window.emui[appId] = [window.emui[appId], app];
@@ -90,6 +95,11 @@ class CAppRegistry {
90
95
  instanceId,
91
96
  documentEle
92
97
  }) => {
98
+ if (!instanceId) {
99
+ throw new Error(
100
+ `instanceId (uuid) is required to register application ${id}`
101
+ );
102
+ }
93
103
  const newAppInstance = {
94
104
  uuid: instanceId,
95
105
  init: null,
@@ -98,11 +108,6 @@ class CAppRegistry {
98
108
  };
99
109
  const appInstances = window.emui[id];
100
110
  if (appInstances) {
101
- if (!instanceId) {
102
- throw new Error(
103
- `Application ${id} is already loaded. uuid is required to load multiple instances of the same app`
104
- );
105
- }
106
111
  if (Array.isArray(appInstances)) {
107
112
  appInstances.push(newAppInstance);
108
113
  } else {
@@ -118,10 +123,10 @@ class CAppRegistry {
118
123
  };
119
124
  /**
120
125
  * delete app from global emui window variable
121
- * @param id.id app id
122
- * @param id.instanceId unique instance id
123
- * @param id.id.id
124
- * @param id.id.instanceId
126
+ * @param id.id
127
+ * @param id app id
128
+ * @param instanceId unique instance id
129
+ * @param id.instanceId
125
130
  */
126
131
  delete = ({ id, instanceId }) => {
127
132
  if (Array.isArray(window.emui[id])) {
@@ -129,6 +134,7 @@ class CAppRegistry {
129
134
  (app) => app.uuid === instanceId
130
135
  );
131
136
  if (index > -1) window.emui[id].splice(index, 1);
137
+ if (window.emui[id].length === 0) delete window.emui[id];
132
138
  } else {
133
139
  delete window.emui[id];
134
140
  }
@@ -33,7 +33,7 @@ __export(app_exports, {
33
33
  MicroAppManager: () => MicroAppManager
34
34
  });
35
35
  module.exports = __toCommonJS(app_exports);
36
- var import_clone = __toESM(require("lodash/clone"), 1);
36
+ var import_cloneDeep = __toESM(require("lodash/cloneDeep"), 1);
37
37
  var import_get = __toESM(require("lodash/get"), 1);
38
38
  var import_set = __toESM(require("lodash/set"), 1);
39
39
  var import_has = __toESM(require("lodash/has"), 1);
@@ -60,10 +60,9 @@ class CAppConfig {
60
60
  this.#baseUrl = (0, import_utils.appendTrailingSlash)(params?.baseUrl || "");
61
61
  }
62
62
  #parse = (data) => {
63
- const { activeEnv } = data;
64
- const activeEnvConfig = data.env[activeEnv] || {};
65
- if (data.env) delete data.env;
66
- this.#gAppConfig = (0, import_merge.default)(data, activeEnvConfig);
63
+ const { activeEnv, env, ...rest } = data;
64
+ const activeEnvConfig = env[activeEnv] || {};
65
+ this.#gAppConfig = (0, import_merge.default)({}, rest, activeEnvConfig);
67
66
  };
68
67
  /**
69
68
  * Get value for the given app config key
@@ -71,14 +70,15 @@ class CAppConfig {
71
70
  * @param defaultValue default value to return if key is not found
72
71
  * @returns value for the given key
73
72
  */
74
- get = (key = "", defaultValue = null) => (0, import_clone.default)((0, import_get.default)(this.#gAppConfig, key, defaultValue));
73
+ get = (key = "", defaultValue = null) => (0, import_cloneDeep.default)((0, import_get.default)(this.#gAppConfig, key, defaultValue));
75
74
  /**
76
75
  * Set value for the given app config key
77
76
  * @param key key to set value for
78
77
  * @param value value to set
79
- * @returns app config instance
80
78
  */
81
- set = (key, value) => (0, import_set.default)(this.#gAppConfig, key, value);
79
+ set = (key, value) => {
80
+ (0, import_set.default)(this.#gAppConfig, key, value);
81
+ };
82
82
  /**
83
83
  * Check if the given key exists in app config
84
84
  * @param key key to check
@@ -104,9 +104,21 @@ class CAppConfig {
104
104
  * @param assetPath url path to load app config from
105
105
  * @param configUrl
106
106
  */
107
+ // eslint-disable-next-line complexity
107
108
  load = async (configUrl) => {
108
109
  const appConfigUrl = configUrl ?? `${this.#getVersionedBaseUrl()}app.config.json`;
109
- const response = await fetch(appConfigUrl);
110
+ let response;
111
+ try {
112
+ response = await fetch(appConfigUrl);
113
+ } catch (err) {
114
+ if (!configUrl && this.#version !== import_constant.LATEST_VERSION) {
115
+ await this.load(`${this.#baseUrl}latest/app.config.json`);
116
+ return;
117
+ }
118
+ throw new Error("Failed to fetch app config", {
119
+ cause: err
120
+ });
121
+ }
110
122
  if (response.ok) {
111
123
  try {
112
124
  const data = await response.json();
@@ -41,7 +41,6 @@ const isCIBuild = () => process.env.CI === "true";
41
41
  const isProduction = (mode) => {
42
42
  if (isCIBuild()) return true;
43
43
  return String(mode).toLowerCase() === import_app.LaunchMode.PRODUCTION.toLowerCase();
44
- return true;
45
44
  };
46
45
  const getPathName = (url) => url ? new URL(url).pathname : "";
47
46
  const getAbsoluteUrl = (url) => {
@@ -97,12 +96,13 @@ const getConfig = ({
97
96
  config,
98
97
  version = "latest"
99
98
  }) => {
100
- const { mode = import_app.LaunchMode.PRODUCTION } = config;
101
- const envConfig = isProduction(mode) ? config.production : config.development;
102
- if (config.production)
103
- delete config.production;
104
- if (config.development)
105
- delete config.development;
99
+ const {
100
+ mode = import_app.LaunchMode.PRODUCTION,
101
+ production,
102
+ development,
103
+ ...restConfig
104
+ } = config;
105
+ const envConfig = isProduction(mode) ? production : development;
106
106
  const newConfig = (0, import_merge.default)(
107
107
  { id },
108
108
  {
@@ -112,7 +112,8 @@ const getConfig = ({
112
112
  securityContext: import_common.SecurityContext.USER,
113
113
  isJsModule: true
114
114
  },
115
- config,
115
+ restConfig,
116
+ { mode },
116
117
  envConfig
117
118
  );
118
119
  newConfig.hostUrl = (0, import_utils.appendTrailingSlash)(
@@ -22,22 +22,22 @@ __export(eventManager_exports, {
22
22
  });
23
23
  module.exports = __toCommonJS(eventManager_exports);
24
24
  var import_uuid = require("uuid");
25
- const flatten = (source, target = []) => {
26
- const retVal = target || [];
27
- if (source && source.forEach) {
28
- source.forEach((item) => {
29
- flatten(item, retVal);
30
- });
31
- } else if (typeof source !== "undefined") {
32
- retVal.push(source);
33
- }
34
- return retVal;
35
- };
36
25
  class EventManager {
37
26
  /**
38
27
  * event listeners
39
28
  */
40
29
  #listeners = /* @__PURE__ */ new Map();
30
+ /**
31
+ * cache for compiled regex patterns used in filter criteria
32
+ */
33
+ #regexCache = /* @__PURE__ */ new WeakMap();
34
+ /**
35
+ * logger instance
36
+ */
37
+ #logger;
38
+ constructor(logger) {
39
+ this.#logger = logger;
40
+ }
41
41
  /**
42
42
  * call an async function with a timeout
43
43
  * @param promise async function to call
@@ -58,21 +58,24 @@ class EventManager {
58
58
  */
59
59
  #emitEvent = (param) => {
60
60
  const { eventName, scriptingObject, eventParams, listeners } = param;
61
- listeners.map(async (listener) => {
61
+ listeners.forEach((listener) => {
62
62
  if (listener.criteria) {
63
63
  const matches = eventParams ? this.#matchesCriteria(eventParams, listener.criteria) : false;
64
64
  if (!matches) {
65
65
  return;
66
66
  }
67
67
  }
68
- try {
69
- await listener.callback({
68
+ Promise.resolve(
69
+ listener.callback({
70
70
  obj: scriptingObject,
71
71
  eventName,
72
72
  eventParams
73
- });
74
- } catch (e) {
75
- }
73
+ })
74
+ ).catch((e) => {
75
+ this.#logger?.warn(
76
+ `Error in event listener for "${eventName}": ${e.message}`
77
+ );
78
+ });
76
79
  });
77
80
  };
78
81
  #emitEventWithFeedback = async ({
@@ -101,7 +104,7 @@ class EventManager {
101
104
  );
102
105
  });
103
106
  const retValues = await Promise.all(promises);
104
- return flatten(retValues);
107
+ return retValues.flat(Infinity).filter((v) => v !== void 0);
105
108
  };
106
109
  /**
107
110
  * Checks if a given payload matches all specified filter criteria.
@@ -135,12 +138,16 @@ class EventManager {
135
138
  return !Number.isNaN(numValue) && numValue < condition.lt;
136
139
  }
137
140
  if ("regex" in condition) {
138
- try {
139
- const regex = new RegExp(condition.regex);
140
- return typeof value === "string" && regex.test(value);
141
- } catch {
142
- return false;
141
+ let regex = this.#regexCache.get(condition);
142
+ if (regex === void 0) {
143
+ try {
144
+ regex = new RegExp(condition.regex);
145
+ } catch {
146
+ regex = null;
147
+ }
148
+ this.#regexCache.set(condition, regex);
143
149
  }
150
+ return regex !== null && typeof value === "string" && regex.test(value);
144
151
  }
145
152
  return false;
146
153
  });
package/dist/cjs/frame.js CHANGED
@@ -40,58 +40,90 @@ const create = ({
40
40
  manifestPath,
41
41
  hostUrl,
42
42
  options
43
- }) => new Promise((resolve, reject) => {
44
- const iframeContainer = document.createElement("div");
45
- iframeContainer.setAttribute(
46
- "style",
47
- "display: flex;width: 100%;height: 100%;flex-direction: column;overflow: hidden;"
48
- );
49
- const frame = document.createElement("iframe");
50
- frame.setAttribute("id", instanceId);
51
- frame.setAttribute("data-testid", id);
52
- frame.setAttribute("title", options.title);
53
- frame.setAttribute("allowfullscreen", "true");
54
- frame.setAttribute("allowtransparency", "true");
55
- if (options.permissionPolicy)
56
- frame.setAttribute("allow", options.permissionPolicy);
57
- if (options.sandbox) frame.setAttribute("sandbox", options.sandbox);
58
- frame.setAttribute(
59
- "style",
60
- options.style ?? "flex-grow: 1;border: none;margin: 0;padding: 0;display: block;min-width: 100%;height: 100%;"
61
- );
62
- const baseSrc = options.src ?? (import_frame.default.default ?? import_frame.default);
63
- const srcWithParams = options.queryParams ? `${baseSrc}${baseSrc.includes("?") ? "&" : "?"}${options.queryParams}` : baseSrc;
64
- frame.setAttribute("src", srcWithParams);
65
- frame.addEventListener("load", () => {
66
- if (!frame.contentDocument) {
67
- reject(new Error("Frame content window is null"));
68
- return;
43
+ }) => (
44
+ // eslint-disable-next-line max-statements
45
+ new Promise((resolve, reject) => {
46
+ const iframeContainer = document.createElement("div");
47
+ iframeContainer.setAttribute(
48
+ "style",
49
+ "display: flex;width: 100%;height: 100%;flex-direction: column;overflow: hidden;"
50
+ );
51
+ const frame = document.createElement("iframe");
52
+ frame.setAttribute("id", instanceId);
53
+ frame.setAttribute("data-testid", id);
54
+ frame.setAttribute("title", options.title);
55
+ frame.setAttribute("allowfullscreen", "true");
56
+ frame.setAttribute("allowtransparency", "true");
57
+ if (options.permissionPolicy)
58
+ frame.setAttribute("allow", options.permissionPolicy);
59
+ if (options.sandbox) frame.setAttribute("sandbox", options.sandbox);
60
+ frame.setAttribute(
61
+ "style",
62
+ options.style ?? "flex-grow: 1;border: none;margin: 0;padding: 0;display: block;min-width: 100%;height: 100%;"
63
+ );
64
+ const baseSrc = options.src ?? (import_frame.default.default ?? import_frame.default);
65
+ let srcWithParams = baseSrc;
66
+ if (options.queryParams) {
67
+ const sanitized = options.queryParams.replace(
68
+ /[^a-zA-Z0-9&=_.~%+-]/g,
69
+ ""
70
+ );
71
+ srcWithParams = `${baseSrc}${baseSrc.includes("?") ? "&" : "?"}${sanitized}`;
69
72
  }
70
- const documentEle = frame.contentDocument;
71
- const ele = documentEle.getElementById(FRAME_APP_CONTAINER_ID_PREFIX);
72
- if (ele) {
73
- ele.id = `${ele.id}${id}`;
74
- }
75
- let baseTag = documentEle.getElementsByTagName("base")?.[0];
76
- if (baseTag) {
77
- baseTag.href = new URL(manifestPath, hostUrl).href;
78
- } else {
79
- baseTag = documentEle.createElement("base");
80
- baseTag.href = new URL(manifestPath, hostUrl).href;
81
- documentEle.getElementsByTagName("head")[0].appendChild(baseTag);
82
- }
83
- resolve(frame);
84
- });
85
- iframeContainer.appendChild(frame);
86
- const { containerId } = options;
87
- const parentElement = document.getElementById(containerId ?? "") ?? document.body;
88
- parentElement.appendChild(iframeContainer);
89
- });
73
+ frame.setAttribute("src", srcWithParams);
74
+ const FRAME_LOAD_TIMEOUT_MS = 1e4;
75
+ let settled = false;
76
+ const timeoutId = setTimeout(() => {
77
+ if (!settled) {
78
+ settled = true;
79
+ reject(
80
+ new Error(
81
+ `iframe for ${id} failed to load within ${FRAME_LOAD_TIMEOUT_MS}ms`
82
+ )
83
+ );
84
+ }
85
+ }, FRAME_LOAD_TIMEOUT_MS);
86
+ frame.addEventListener("error", () => {
87
+ if (!settled) {
88
+ settled = true;
89
+ clearTimeout(timeoutId);
90
+ reject(new Error(`iframe for ${id} failed to load`));
91
+ }
92
+ });
93
+ frame.addEventListener("load", () => {
94
+ if (settled) return;
95
+ settled = true;
96
+ clearTimeout(timeoutId);
97
+ if (!frame.contentDocument) {
98
+ reject(new Error("Frame content window is null"));
99
+ return;
100
+ }
101
+ const documentEle = frame.contentDocument;
102
+ const ele = documentEle.getElementById(FRAME_APP_CONTAINER_ID_PREFIX);
103
+ if (ele) {
104
+ ele.id = `${ele.id}${id}`;
105
+ }
106
+ let baseTag = documentEle.getElementsByTagName("base")?.[0];
107
+ if (baseTag) {
108
+ baseTag.href = new URL(manifestPath, hostUrl).href;
109
+ } else {
110
+ baseTag = documentEle.createElement("base");
111
+ baseTag.href = new URL(manifestPath, hostUrl).href;
112
+ documentEle.getElementsByTagName("head")[0].appendChild(baseTag);
113
+ }
114
+ resolve(frame);
115
+ });
116
+ iframeContainer.appendChild(frame);
117
+ const { containerId } = options;
118
+ const parentElement = document.getElementById(containerId ?? "") ?? document.body;
119
+ parentElement.appendChild(iframeContainer);
120
+ })
121
+ );
90
122
  const get = (instanceId) => document.getElementById(instanceId);
91
123
  const remove = (instanceId) => {
92
124
  const frameEle = get(instanceId);
93
125
  if (frameEle) {
94
- frameEle.remove();
126
+ frameEle.parentElement?.remove();
95
127
  }
96
128
  };
97
129
  const Frame = {
@@ -6,7 +6,7 @@
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Host</title>
8
8
  <script src="https://cdn.tailwindcss.com?plugins=forms"></script>
9
- <script src="https://cdn.qa1.ice.com/pui-diagnostics@3" ></script>
9
+ <script src="https://cdn.mortgagetech.q1.ice.com/pui-diagnostics@3" ></script>
10
10
  </head>
11
11
  <body>
12
12
  <header class="bg-indigo-300 h-10 flex place-items-center">
package/dist/cjs/index.js CHANGED
@@ -20,10 +20,17 @@ var index_exports = {};
20
20
  __export(index_exports, {
21
21
  CAppBridge: () => import_appBridge.CAppBridge,
22
22
  Event: () => import_microfe_common.Event,
23
+ LaunchMode: () => import_app.LaunchMode,
24
+ MicroAppManager: () => import_app.MicroAppManager,
25
+ ScriptLoader: () => import_script.ScriptLoader,
23
26
  ScriptingObject: () => import_microfe_common.ScriptingObject,
24
- SecurityContext: () => import_common.SecurityContext
27
+ SecurityContext: () => import_common.SecurityContext,
28
+ StyleLoader: () => import_style.StyleLoader
25
29
  });
26
30
  module.exports = __toCommonJS(index_exports);
27
31
  var import_common = require("./typings/common.js");
32
+ var import_app = require("./config/app.js");
28
33
  var import_microfe_common = require("@elliemae/microfe-common");
29
34
  var import_appBridge = require("./appBridge.js");
35
+ var import_script = require("./loaders/script.js");
36
+ var import_style = require("./loaders/style.js");