@elliemae/pui-app-bridge 2.9.4 → 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.
Files changed (102) hide show
  1. package/dist/cjs/appBridge.js +380 -93
  2. package/dist/cjs/appRegistry.js +136 -0
  3. package/dist/cjs/config/app.js +15 -2
  4. package/dist/cjs/config/microFE.js +3 -3
  5. package/dist/cjs/eventManager.js +16 -16
  6. package/dist/cjs/frame.html +2 -2
  7. package/dist/cjs/frame.js +39 -14
  8. package/dist/cjs/index.html +1 -1
  9. package/dist/cjs/index.js +3 -3
  10. package/dist/cjs/loaders/script.js +5 -5
  11. package/dist/cjs/loaders/style.js +1 -0
  12. package/dist/cjs/microfeHost.js +51 -31
  13. package/dist/cjs/tests/flights/23.1/app.checksum1.js +25 -24
  14. package/dist/cjs/tests/flights/latest/app.checksum.js +25 -24
  15. package/dist/cjs/tests/hotels/23.1/app.checksum.js +27 -24
  16. package/dist/cjs/tests/hotels/latest/app.checksum.js +27 -24
  17. package/dist/cjs/tests/loan/latest/index.js +49 -57
  18. package/dist/cjs/tests/scriptingObjects/analytics.js +7 -7
  19. package/dist/cjs/tests/scriptingObjects/appraisalServiceModule.js +8 -8
  20. package/dist/cjs/tests/scriptingObjects/global.js +1 -2
  21. package/dist/cjs/tests/task/latest/index.dev.js +29 -28
  22. package/dist/cjs/tests/task/latest/index.js +29 -28
  23. package/dist/cjs/tests/travelhub/23.1/app.checksum.js +24 -26
  24. package/dist/cjs/tests/travelhub/23.1/landing.checksum1.js +5 -7
  25. package/dist/cjs/utils.js +31 -1
  26. package/dist/esm/appBridge.js +390 -95
  27. package/dist/esm/appRegistry.js +116 -0
  28. package/dist/esm/config/app.js +15 -2
  29. package/dist/esm/config/microFE.js +3 -3
  30. package/dist/esm/eventManager.js +16 -16
  31. package/dist/esm/frame.html +2 -2
  32. package/dist/esm/frame.js +29 -14
  33. package/dist/esm/index.html +1 -1
  34. package/dist/esm/loaders/script.js +5 -5
  35. package/dist/esm/loaders/style.js +1 -0
  36. package/dist/esm/microfeHost.js +55 -31
  37. package/dist/esm/tests/flights/23.1/app.checksum1.js +25 -24
  38. package/dist/esm/tests/flights/latest/app.checksum.js +25 -24
  39. package/dist/esm/tests/hotels/23.1/app.checksum.js +27 -24
  40. package/dist/esm/tests/hotels/latest/app.checksum.js +27 -24
  41. package/dist/esm/tests/loan/latest/index.js +49 -57
  42. package/dist/esm/tests/scriptingObjects/analytics.js +7 -7
  43. package/dist/esm/tests/scriptingObjects/appraisalServiceModule.js +8 -8
  44. package/dist/esm/tests/scriptingObjects/global.js +1 -2
  45. package/dist/esm/tests/task/latest/index.dev.js +29 -28
  46. package/dist/esm/tests/task/latest/index.js +29 -28
  47. package/dist/esm/tests/travelhub/23.1/app.checksum.js +24 -26
  48. package/dist/esm/tests/travelhub/23.1/landing.checksum1.js +5 -7
  49. package/dist/esm/utils.js +31 -1
  50. package/dist/public/assets/frame.671d9de68be598da64ca.html +47 -0
  51. package/dist/public/frame.html +1 -1
  52. package/dist/public/index.html +1 -1
  53. package/dist/public/js/emuiAppBridge.40c8880c94dbc97b49fd.js +51 -0
  54. package/dist/public/js/emuiAppBridge.40c8880c94dbc97b49fd.js.br +0 -0
  55. package/dist/public/js/emuiAppBridge.40c8880c94dbc97b49fd.js.gz +0 -0
  56. package/dist/public/js/emuiAppBridge.40c8880c94dbc97b49fd.js.map +1 -0
  57. package/dist/public/loan-object.js +1 -1
  58. package/dist/public/loan-object.js.br +0 -0
  59. package/dist/public/loan-object.js.gz +0 -0
  60. package/dist/public/loan-object.js.map +1 -1
  61. package/dist/types/lib/appBridge.d.ts +38 -28
  62. package/dist/types/lib/appRegistry.d.ts +41 -0
  63. package/dist/types/lib/eventManager.d.ts +4 -4
  64. package/dist/types/lib/frame.d.ts +45 -4
  65. package/dist/types/lib/index.d.ts +3 -3
  66. package/dist/types/lib/loaders/script.d.ts +2 -1
  67. package/dist/types/lib/microfeHost.d.ts +15 -25
  68. package/dist/types/lib/tests/flights/23.1/app.checksum1.d.ts +7 -0
  69. package/dist/types/lib/tests/flights/latest/app.checksum.d.ts +7 -0
  70. package/dist/types/lib/tests/hotels/23.1/app.checksum.d.ts +7 -0
  71. package/dist/types/lib/tests/hotels/latest/app.checksum.d.ts +7 -0
  72. package/dist/types/lib/tests/loan/latest/index.d.ts +11 -0
  73. package/dist/types/lib/tests/scriptingObjects/analytics.d.ts +3 -3
  74. package/dist/types/lib/tests/scriptingObjects/appraisalServiceModule.d.ts +2 -1
  75. package/dist/types/lib/tests/task/latest/index.d.ts +10 -0
  76. package/dist/types/lib/tests/task/latest/index.dev.d.ts +10 -0
  77. package/dist/types/lib/tests/travelhub/23.1/app.checksum.d.ts +7 -0
  78. package/dist/types/lib/tests/travelhub/23.1/landing.checksum1.d.ts +2 -0
  79. package/dist/types/lib/typings/appInfo.d.ts +1 -0
  80. package/dist/types/lib/typings/common.d.ts +0 -66
  81. package/dist/types/lib/typings/guest.d.ts +10 -3
  82. package/dist/types/lib/typings/host.d.ts +32 -32
  83. package/dist/types/lib/typings/window.d.ts +6 -1
  84. package/dist/types/lib/utils.d.ts +7 -0
  85. package/dist/types/tsconfig.tsbuildinfo +1 -1
  86. package/dist/umd/671d9de68be598da64ca.html +47 -0
  87. package/dist/umd/frame.html +1 -1
  88. package/dist/umd/index.html +1 -1
  89. package/dist/umd/index.js +35 -9
  90. package/dist/umd/index.js.br +0 -0
  91. package/dist/umd/index.js.gz +0 -0
  92. package/dist/umd/index.js.map +1 -1
  93. package/dist/umd/loan-object.js +1 -1
  94. package/dist/umd/loan-object.js.br +0 -0
  95. package/dist/umd/loan-object.js.gz +0 -0
  96. package/dist/umd/loan-object.js.map +1 -1
  97. package/package.json +12 -12
  98. package/dist/public/js/emuiAppBridge.34df989fae2296115611.js +0 -25
  99. package/dist/public/js/emuiAppBridge.34df989fae2296115611.js.br +0 -0
  100. package/dist/public/js/emuiAppBridge.34df989fae2296115611.js.gz +0 -0
  101. package/dist/public/js/emuiAppBridge.34df989fae2296115611.js.map +0 -1
  102. package/dist/types/lib/tests/pubsubAPI.test.d.ts +0 -1
@@ -0,0 +1,116 @@
1
+ class CAppRegistry {
2
+ constructor() {
3
+ if (!window.emui) {
4
+ window.emui = {};
5
+ }
6
+ window.emui.registerApp = this.#registerApp;
7
+ }
8
+ /**
9
+ * global method for guest apps to register themselves with parent
10
+ * @param param0
11
+ * @param param0.appId
12
+ * @param param0.app
13
+ */
14
+ #registerApp = ({ appId, app }) => {
15
+ if (!app?.uuid) throw new Error("application uuid is required");
16
+ window.emui[appId] = window.emui[appId] || [];
17
+ if (Array.isArray(window.emui[appId])) {
18
+ const appIndex = window.emui[appId].findIndex(
19
+ (eApp) => eApp.uuid === app.uuid
20
+ );
21
+ if (appIndex > -1) {
22
+ window.emui[appId][appIndex] = app;
23
+ } else {
24
+ window.emui[appId].push(app);
25
+ }
26
+ } else {
27
+ let existingApp = window.emui[appId];
28
+ if (existingApp?.uuid === app.uuid) {
29
+ existingApp = { ...existingApp, ...app };
30
+ window.emui[appId] = [existingApp];
31
+ } else if (typeof existingApp.init === void 0) {
32
+ window.emui[appId] = [{ ...existingApp, ...app }];
33
+ } else {
34
+ window.emui[appId] = [window.emui[appId], app];
35
+ }
36
+ }
37
+ };
38
+ /**
39
+ * get micro app guest from window object
40
+ * @param param0 id and uuid
41
+ * @param param0.id app id
42
+ * @param param0.uuid unique instance id
43
+ * @param param0.instanceId
44
+ * @returns micro app guest
45
+ */
46
+ get = ({ id, instanceId }) => {
47
+ const apps = window.emui?.[id];
48
+ if (Array.isArray(apps)) {
49
+ const app = apps.find((eApp) => eApp.uuid === instanceId);
50
+ return app ?? null;
51
+ }
52
+ if (apps?.uuid === instanceId) {
53
+ return apps;
54
+ }
55
+ return null;
56
+ };
57
+ /**
58
+ * add app to global emui window variable
59
+ * @param id.id
60
+ * @param id app id
61
+ * @param instanceId unique instance id
62
+ * @param id.instanceId
63
+ * @param id.documentEle
64
+ */
65
+ add = ({
66
+ id,
67
+ instanceId,
68
+ documentEle
69
+ }) => {
70
+ const newAppInstance = {
71
+ uuid: instanceId,
72
+ init: null,
73
+ mount: null,
74
+ unmount: null
75
+ };
76
+ const appInstances = window.emui[id];
77
+ if (appInstances) {
78
+ if (!instanceId) {
79
+ throw new Error(
80
+ `Application ${id} is already loaded. uuid is required to load multiple instances of the same app`
81
+ );
82
+ }
83
+ if (Array.isArray(appInstances)) {
84
+ appInstances.push(newAppInstance);
85
+ } else {
86
+ window.emui[id] = [appInstances, newAppInstance];
87
+ }
88
+ } else {
89
+ window.emui[id] = [newAppInstance];
90
+ }
91
+ if (documentEle.defaultView) {
92
+ documentEle.defaultView.emui = documentEle.defaultView.emui ?? {};
93
+ documentEle.defaultView.emui.uuid = instanceId;
94
+ }
95
+ };
96
+ /**
97
+ * delete app from global emui window variable
98
+ * @param id.id app id
99
+ * @param id.instanceId unique instance id
100
+ * @param id.id.id
101
+ * @param id.id.instanceId
102
+ */
103
+ delete = ({ id, instanceId }) => {
104
+ if (Array.isArray(window.emui[id])) {
105
+ const index = window.emui[id].findIndex(
106
+ (app) => app.uuid === instanceId
107
+ );
108
+ if (index > -1) window.emui[id].splice(index, 1);
109
+ } else {
110
+ delete window.emui[id];
111
+ }
112
+ };
113
+ }
114
+ export {
115
+ CAppRegistry
116
+ };
@@ -40,14 +40,27 @@ class CAppConfig {
40
40
  * @returns true if key exists
41
41
  */
42
42
  has = (key = "") => lodashHas(this.#gAppConfig, key);
43
+ /**
44
+ * add version to the base url
45
+ * @returns versioned base url
46
+ */
47
+ #getVersionedBaseUrl = () => {
48
+ const regex = /(?:\/)(\d+\.\d+|latest)(?:\/?)?$/;
49
+ if (!regex.test(this.#baseUrl)) {
50
+ const majorMinorVersion = this.#version.match(/^(?:\d+\.\d+)*/g);
51
+ return appendTrailingSlash(
52
+ `${this.#baseUrl}${majorMinorVersion?.[0] || LATEST_VERSION}`
53
+ );
54
+ }
55
+ return this.#baseUrl;
56
+ };
43
57
  /**
44
58
  * load application configuration from the given asset path
45
59
  * @param assetPath url path to load app config from
46
60
  * @param configUrl
47
61
  */
48
62
  load = async (configUrl) => {
49
- const majorMinorVersion = this.#version.match(/^(?:\d+\.\d+)*/g);
50
- const appConfigUrl = configUrl ?? `${this.#baseUrl}${majorMinorVersion && majorMinorVersion[0] || LATEST_VERSION}/app.config.json`;
63
+ const appConfigUrl = configUrl ?? `${this.#getVersionedBaseUrl()}app.config.json`;
51
64
  const response = await fetch(appConfigUrl);
52
65
  if (response.ok) {
53
66
  try {
@@ -69,7 +69,8 @@ const getConfig = ({
69
69
  name: id,
70
70
  mode: "production",
71
71
  manifestPath: "./{SYSTEM_VERSION}/",
72
- securityContext: SecurityContext.USER
72
+ securityContext: SecurityContext.USER,
73
+ isJsModule: true
73
74
  },
74
75
  config,
75
76
  envConfig
@@ -90,8 +91,7 @@ class CMicroFEConfig {
90
91
  appConfig
91
92
  }) => {
92
93
  const mfeAppsFromConfig = appConfig.get(CONFIG_KEY);
93
- if (!mfeAppsFromConfig)
94
- throw new Error("app.config.json is missing microFrontendApps section");
94
+ if (!mfeAppsFromConfig) return;
95
95
  this.#microFrontendApps = Object.keys(mfeAppsFromConfig).map(
96
96
  (appId) => {
97
97
  validate(appId, mfeAppsFromConfig[appId]);
@@ -70,17 +70,19 @@ class EventManager {
70
70
  };
71
71
  /**
72
72
  * dispatch an event
73
+ * @param scriptingObject
73
74
  * @param {DispatchEventParam<EventId, Params>} param - parameters for dispatching an event
74
75
  */
75
- dispatchEvent = async (param) => {
76
+ dispatchEvent = async (scriptingObject, param) => {
76
77
  const {
77
- event: { id, name, requiresFeedback, scriptingObject },
78
+ event: { id, name },
78
79
  eventParams,
79
- feedbackWaitTime = 1e3
80
+ eventOptions
80
81
  } = param;
82
+ const { timeout } = eventOptions ?? {};
81
83
  if (!id) throw new Error("Event Id is required");
82
84
  const listeners = this.#listeners.get(id) || [];
83
- if (!requiresFeedback) {
85
+ if (!timeout || timeout <= 0) {
84
86
  this.#emitEvent({
85
87
  eventName: name,
86
88
  scriptingObject,
@@ -94,7 +96,7 @@ class EventManager {
94
96
  eventName: name,
95
97
  scriptingObject,
96
98
  eventParams,
97
- feedbackWaitTime
99
+ feedbackWaitTime: timeout
98
100
  });
99
101
  };
100
102
  /**
@@ -102,30 +104,28 @@ class EventManager {
102
104
  * @param {SubscribeParam<EventId, AppEvents[EventId]>} param - parameters for subscribing to an event
103
105
  */
104
106
  subscribe = (param) => {
105
- const { eventId, listener } = param;
107
+ const { eventId, callback } = param;
106
108
  if (!eventId) throw new Error("eventId is required");
107
- if (!listener) throw new Error("Listener is required");
109
+ if (!callback) throw new Error("Callback is required");
108
110
  const listeners = this.#listeners.get(eventId) || [];
109
- const subscriptionId = uuidv4();
111
+ const token = uuidv4();
110
112
  listeners.push({
111
- subscriptionId,
112
- callback: listener
113
+ token,
114
+ callback
113
115
  });
114
116
  this.#listeners.set(eventId, listeners);
115
- return subscriptionId;
117
+ return token;
116
118
  };
117
119
  /**
118
120
  * Unsubscribe from an event
119
121
  * @param {UnsubscribeParam<EventId>} param - parameters for unsubscribing from an event
120
122
  */
121
123
  unsubscribe = (param) => {
122
- const { eventId, subscriptionId } = param;
124
+ const { eventId, token } = param;
123
125
  if (!eventId) throw new Error("eventId id is required");
124
- if (subscriptionId) {
126
+ if (token) {
125
127
  const listeners = this.#listeners.get(eventId) || [];
126
- const index = listeners.findIndex(
127
- (listener) => listener.subscriptionId === subscriptionId
128
- );
128
+ const index = listeners.findIndex((listener) => listener.token === token);
129
129
  if (index > -1) {
130
130
  listeners.splice(index, 1);
131
131
  this.#listeners.set(eventId, listeners);
@@ -6,7 +6,7 @@
6
6
  <meta name="mobile-web-app-capable" content="yes" />
7
7
  <link rel="icon" href="/favicon.ico" />
8
8
  <title>Application</title>
9
- <script>
9
+ <script nonce="__CSP_NONCE__">
10
10
  (function (i, s, o, g, r, a, m) {
11
11
  i['GoogleAnalyticsObject'] = r;
12
12
  (i[r] =
@@ -27,7 +27,7 @@
27
27
  'ga',
28
28
  );
29
29
  </script>
30
- <style>
30
+ <style nonce="__CSP_NONCE__">
31
31
  .full-width {
32
32
  width: 100%;
33
33
  }
package/dist/esm/frame.js CHANGED
@@ -1,23 +1,35 @@
1
- const FRAME_CONTAINER_ID_PREFIX = "pui-iframe-container-";
1
+ import frameHtml from "./frame.html?resource";
2
2
  const FRAME_APP_CONTAINER_ID_PREFIX = "pui-app-container-";
3
- const create = (appId, options) => new Promise((resolve, reject) => {
3
+ const create = ({
4
+ id,
5
+ instanceId,
6
+ manifestPath,
7
+ hostUrl,
8
+ options
9
+ }) => new Promise((resolve, reject) => {
4
10
  const iframeContainer = document.createElement("div");
5
11
  iframeContainer.setAttribute(
6
12
  "style",
7
13
  "display: flex;width: 100%;height: 100%;flex-direction: column;overflow: hidden;"
8
14
  );
9
15
  const frame = document.createElement("iframe");
10
- frame.setAttribute("id", `${FRAME_CONTAINER_ID_PREFIX}${appId}`);
16
+ frame.setAttribute("id", instanceId);
17
+ frame.setAttribute("data-testid", id);
11
18
  frame.setAttribute("title", options.title);
12
19
  frame.setAttribute("allowfullscreen", "true");
13
20
  frame.setAttribute("allowtransparency", "true");
14
- frame.setAttribute("allow", "microphone; camera");
21
+ if (options.permissionPolicy)
22
+ frame.setAttribute("allow", options.permissionPolicy);
15
23
  if (options.sandbox) frame.setAttribute("sandbox", options.sandbox);
16
24
  frame.setAttribute(
17
25
  "style",
18
26
  options.style ?? "flex-grow: 1;border: none;margin: 0;padding: 0;display: block;min-width: 100%;height: 100%;"
19
27
  );
20
- frame.setAttribute("src", options.src ?? "./frame.html");
28
+ frame.setAttribute(
29
+ "src",
30
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
31
+ options.src ?? (frameHtml.default ?? frameHtml)
32
+ );
21
33
  frame.addEventListener("load", () => {
22
34
  if (!frame.contentDocument) {
23
35
  reject(new Error("Frame content window is null"));
@@ -26,7 +38,15 @@ const create = (appId, options) => new Promise((resolve, reject) => {
26
38
  const documentEle = frame.contentDocument;
27
39
  const ele = documentEle.getElementById(FRAME_APP_CONTAINER_ID_PREFIX);
28
40
  if (ele) {
29
- ele.id = `${ele.id}${appId}`;
41
+ ele.id = `${ele.id}${id}`;
42
+ }
43
+ let baseTag = documentEle.getElementsByTagName("base")?.[0];
44
+ if (baseTag) {
45
+ baseTag.href = new URL(manifestPath, hostUrl).href;
46
+ } else {
47
+ baseTag = documentEle.createElement("base");
48
+ baseTag.href = new URL(manifestPath, hostUrl).href;
49
+ documentEle.getElementsByTagName("head")[0].appendChild(baseTag);
30
50
  }
31
51
  resolve(frame);
32
52
  });
@@ -35,13 +55,9 @@ const create = (appId, options) => new Promise((resolve, reject) => {
35
55
  const parentElement = document.getElementById(containerId ?? "") ?? document.body;
36
56
  parentElement.appendChild(iframeContainer);
37
57
  });
38
- const get = (appId) => document.getElementById(
39
- `${FRAME_CONTAINER_ID_PREFIX}${appId}`
40
- );
41
- const remove = (appId) => {
42
- const frameEle = document.getElementById(
43
- `${FRAME_CONTAINER_ID_PREFIX}${appId}`
44
- );
58
+ const get = (instanceId) => document.getElementById(instanceId);
59
+ const remove = (instanceId) => {
60
+ const frameEle = get(instanceId);
45
61
  if (frameEle) {
46
62
  frameEle.remove();
47
63
  }
@@ -53,6 +69,5 @@ const Frame = {
53
69
  };
54
70
  export {
55
71
  FRAME_APP_CONTAINER_ID_PREFIX,
56
- FRAME_CONTAINER_ID_PREFIX,
57
72
  Frame
58
73
  };
@@ -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://qa.assets.rd.elliemae.io/pui-diagnostics@3" ></script>
9
+ <script src="https://cdn.qa1.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">
@@ -1,7 +1,5 @@
1
1
  import { removeDoubleSlash, isJSDOM } from "../utils.js";
2
2
  const APP_SCRIPT_ID_PREFIX = "ice-script-";
3
- const HEAD_SCRIPTS = /(?:emuiDiagnostics|global|global-prod|emuiUserMonitoring)(?:..*)?.js/;
4
- const isDeferEligible = (scriptSrc) => !HEAD_SCRIPTS.test(scriptSrc);
5
3
  class ScriptLoader {
6
4
  #logger;
7
5
  constructor(logger) {
@@ -12,12 +10,16 @@ class ScriptLoader {
12
10
  hostUrl,
13
11
  documentEle,
14
12
  fileName,
15
- index
13
+ index,
14
+ isJsModule = true
16
15
  }) => new Promise((resolve, reject) => {
17
16
  const url = new URL(fileName, hostUrl);
18
17
  const ele = documentEle.createElement("script");
19
18
  ele.id = `${APP_SCRIPT_ID_PREFIX}${name.toLowerCase()}-${index}`;
20
19
  ele.src = removeDoubleSlash(url.href);
20
+ ele.nonce = "__CSP_NONCE__";
21
+ if (!isJSDOM() && isJsModule) ele.type = "module";
22
+ else ele.async = false;
21
23
  ele.onload = resolve.bind(null, ele.id);
22
24
  ele.onerror = (err) => {
23
25
  reject(
@@ -26,8 +28,6 @@ class ScriptLoader {
26
28
  })
27
29
  );
28
30
  };
29
- ele.async = false;
30
- if (!isJSDOM() && isDeferEligible(ele.src)) ele.defer = true;
31
31
  documentEle.head.appendChild(ele);
32
32
  });
33
33
  remove = (elementId = "", documentEle = document) => new Promise((resolve) => {
@@ -14,6 +14,7 @@ class StyleLoader {
14
14
  }) => new Promise((resolve, reject) => {
15
15
  const ele = documentEle.createElement("link");
16
16
  ele.id = `${APP_STYLE_ID_PREFIX}${name.toLowerCase()}-${index}`;
17
+ ele.nonce = "__CSP_NONCE__";
17
18
  ele.rel = "stylesheet";
18
19
  const url = new URL(fileName, hostUrl);
19
20
  ele.href = removeDoubleSlash(url.href);
@@ -1,8 +1,15 @@
1
- import { subscribe, unsubscribe } from "pubsub-js";
2
- import { FRAME_CONTAINER_ID_PREFIX } from "./frame.js";
1
+ import {
2
+ Event,
3
+ isPublicFunction,
4
+ ScriptingObjectProxy
5
+ } from "@elliemae/microfe-common";
3
6
  import { LATEST_VERSION } from "./constant.js";
4
7
  class CMicroFEHost {
5
8
  #logger;
9
+ /**
10
+ * unique id of the iframe container
11
+ */
12
+ #containerId;
6
13
  #guest;
7
14
  #version;
8
15
  #soManager;
@@ -14,16 +21,11 @@ class CMicroFEHost {
14
21
  constructor(params) {
15
22
  this.#guest = params.guest;
16
23
  this.#logger = params.logger;
24
+ this.#containerId = params.containerId;
17
25
  this.#version = params?.version || LATEST_VERSION;
18
26
  this.#soManager = params.soManager;
19
27
  this.#eventManager = params.eventManager;
20
28
  }
21
- /**
22
- * add listener to the scripting object event
23
- * @param {SubscribeParam<EventId, EventListener>} params - parameters to add event listener
24
- * @returns subscription id
25
- */
26
- addEventListener = (params) => this.#eventManager.subscribe(params);
27
29
  /**
28
30
  * application release version
29
31
  * @returns release version
@@ -37,43 +39,65 @@ class CMicroFEHost {
37
39
  * @param objectId
38
40
  * @returns scripting object reference
39
41
  */
40
- getObject = (objectId) => Promise.resolve(this.#soManager.getObject(objectId, this.#guest));
41
- /**
42
- * removes listener from the scripting object event
43
- * @param {UnsubscribeParam<EventId>} params - parameters to remove event listener
44
- */
45
- removeEventListener = (params) => {
46
- this.#eventManager.unsubscribe(params);
42
+ getObject = (objectId) => {
43
+ const so = this.#soManager.getObject(objectId, this.#guest);
44
+ if (so) {
45
+ const proxy = new ScriptingObjectProxy(so.id, so.objectType);
46
+ Object.keys(so).forEach((propName) => {
47
+ const propValue = so[propName];
48
+ if (propValue instanceof Event) {
49
+ Object.defineProperty(proxy, propName, {
50
+ value: new Event({
51
+ name: propName,
52
+ objectId: so.id
53
+ }),
54
+ enumerable: true
55
+ });
56
+ } else if (isPublicFunction(propValue, propName)) {
57
+ Object.defineProperty(proxy, propName, {
58
+ value: (...args) => {
59
+ Object.defineProperty(propValue, "callContext", {
60
+ value: { guest: this.#guest },
61
+ configurable: true,
62
+ enumerable: true,
63
+ writable: true
64
+ });
65
+ return so[propName](
66
+ ...args
67
+ );
68
+ },
69
+ enumerable: true
70
+ });
71
+ }
72
+ });
73
+ return Promise.resolve(proxy);
74
+ }
75
+ return Promise.resolve(null);
47
76
  };
48
77
  /**
49
78
  * set the size of the guest application iframe window
50
79
  * @param {AppWindowSize} appSize window size of the application
51
80
  */
52
81
  setAppWindowSize = (appSize) => {
53
- const { appId, size } = appSize;
54
- const frameEle = document.getElementById(
55
- `${FRAME_CONTAINER_ID_PREFIX}${appId}`
56
- );
82
+ if (!this.#containerId) return;
83
+ const { size } = appSize;
84
+ const frameEle = document.getElementById(this.#containerId);
57
85
  if (frameEle) {
58
86
  frameEle.style.height = `${size.height}px`;
59
87
  }
60
88
  };
61
- // deprecated legacy eventing methods (to be removed)
62
89
  /**
63
- * subscribe to an scripting object event (deprecated)
64
- * @param eventId unique id of the event. The format is [scripting object name].[event name]
65
- * @param listener callback function to be called when the event is fired
66
- * @returns token to be used to unsubscribe
90
+ * add listener to the scripting object event
91
+ * @param {SubscribeParam<EventId, EventListener>} params - parameters to add event listener
92
+ * @returns subscription id
67
93
  */
68
- // eslint-disable-next-line @typescript-eslint/ban-types
69
- subscribe = (eventId, listener) => subscribe(eventId, listener);
94
+ subscribe = (params) => this.#eventManager.subscribe(params);
70
95
  /**
71
- * unsubscribe from an scripting object event (deprecated)
72
- * @param token unique token returned by subscribe
73
- * @param eventId unique id of the event. The format is [scripting object name].[event name]
96
+ * removes listener from the scripting object event
97
+ * @param {UnsubscribeParam<EventId>} params - parameters to remove event listener
74
98
  */
75
- unsubscribe = (token) => {
76
- unsubscribe(token);
99
+ unsubscribe = (params) => {
100
+ this.#eventManager.unsubscribe(params);
77
101
  };
78
102
  }
79
103
  export {
@@ -1,27 +1,26 @@
1
- (function() {
2
- const appId = "flights";
3
- const appName = "Flights App";
4
- const getWindow = () => {
5
- try {
6
- window.parent.document;
7
- return window.parent;
8
- } catch (err) {
9
- return window;
10
- }
11
- };
12
- let host = null;
13
- let parentHistory = null;
14
- let logger = null;
15
- const browserWindow = getWindow();
16
- browserWindow.emui = browserWindow.emui || {};
17
- browserWindow.emui[appId] = browserWindow.emui[appId] || {};
18
- browserWindow.emui[appId].init = async (options) => {
1
+ const appId = "flights";
2
+ const appName = "Flights App";
3
+ const getWindow = () => {
4
+ try {
5
+ window.parent.document;
6
+ return window.parent;
7
+ } catch (err) {
8
+ return window;
9
+ }
10
+ };
11
+ let host = null;
12
+ let parentHistory = null;
13
+ let logger = null;
14
+ window.emui = window.emui || { uuid: crypto.randomUUID() };
15
+ window.emui.app = {
16
+ uuid: window.emui.uuid,
17
+ init: async (options) => {
19
18
  host = options.host;
20
19
  parentHistory = options.history;
21
20
  logger = options.logger;
22
21
  return Promise.resolve();
23
- };
24
- browserWindow.emui[appId].mount = async () => {
22
+ },
23
+ mount: async () => {
25
24
  const mainElement = document.createElement("main");
26
25
  const pageHeaderEle = document.createElement("h1");
27
26
  pageHeaderEle.textContent = appName;
@@ -33,10 +32,12 @@
33
32
  mainElement.appendChild(versionEle);
34
33
  document.body.appendChild(mainElement);
35
34
  return Promise.resolve();
36
- };
37
- browserWindow.emui[appId].unmount = () => {
35
+ },
36
+ unmount: () => {
38
37
  const mainEle = document.getElementsByTagName("main")[0];
39
38
  if (mainEle) mainEle.remove();
40
39
  return Promise.resolve();
41
- };
42
- })();
40
+ }
41
+ };
42
+ const browserWindow = getWindow();
43
+ browserWindow.emui?.registerApp?.({ appId, app: window.emui.app });
@@ -1,27 +1,26 @@
1
- (function() {
2
- const appId = "flights";
3
- const appName = "Flights App";
4
- const getWindow = () => {
5
- try {
6
- window.parent.document;
7
- return window.parent;
8
- } catch (err) {
9
- return window;
10
- }
11
- };
12
- let host = null;
13
- let parentHistory = null;
14
- let logger = null;
15
- const browserWindow = getWindow();
16
- browserWindow.emui = browserWindow.emui || {};
17
- browserWindow.emui[appId] = browserWindow.emui[appId] || {};
18
- browserWindow.emui[appId].init = async (options) => {
1
+ const appId = "flights";
2
+ const appName = "Flights App";
3
+ const getWindow = () => {
4
+ try {
5
+ window.parent.document;
6
+ return window.parent;
7
+ } catch (err) {
8
+ return window;
9
+ }
10
+ };
11
+ let host = null;
12
+ let parentHistory = null;
13
+ let logger = null;
14
+ window.emui = window.emui || { uuid: crypto.randomUUID() };
15
+ window.emui.app = {
16
+ uuid: window.emui.uuid,
17
+ init: async (options) => {
19
18
  host = options.host;
20
19
  parentHistory = options.history;
21
20
  logger = options.logger;
22
21
  return Promise.resolve();
23
- };
24
- browserWindow.emui[appId].mount = async () => {
22
+ },
23
+ mount: async () => {
25
24
  const mainElement = document.createElement("main");
26
25
  const pageHeaderEle = document.createElement("h1");
27
26
  pageHeaderEle.textContent = appName;
@@ -33,10 +32,12 @@
33
32
  mainElement.appendChild(versionEle);
34
33
  document.body.appendChild(mainElement);
35
34
  return Promise.resolve();
36
- };
37
- browserWindow.emui[appId].unmount = () => {
35
+ },
36
+ unmount: () => {
38
37
  const mainEle = document.getElementsByTagName("main")[0];
39
38
  if (mainEle) mainEle.remove();
40
39
  return Promise.resolve();
41
- };
42
- })();
40
+ }
41
+ };
42
+ const browserWindow = getWindow();
43
+ browserWindow.emui?.registerApp?.({ appId, app: window.emui.app });