@elliemae/microfe-common 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.
package/dist/cjs/event.js CHANGED
@@ -58,9 +58,9 @@ class ProxyEvent {
58
58
  * @returns true if given object is an instance of ProxyEvent
59
59
  */
60
60
  static [Symbol.hasInstance](obj) {
61
- return obj.getType?.() === "ProxyEvent";
61
+ return typeof obj === "object" && obj !== null && "getType" in obj && typeof obj.getType === "function" && obj.getType() === "ProxyEvent";
62
62
  }
63
- /* eslint-enbale indent */
63
+ /* eslint-enable indent */
64
64
  /**
65
65
  * module that owns this event management. SSF Guest or App Bridge host
66
66
  */
@@ -90,6 +90,9 @@ class ProxyEvent {
90
90
  */
91
91
  constructor(param) {
92
92
  const { name, objectId, eventSrc } = param;
93
+ if (!name) throw new Error("Event name is required");
94
+ if (!objectId) throw new Error("Scripting object id is required");
95
+ if (!eventSrc) throw new Error("Event source is required");
93
96
  this.objectId = objectId;
94
97
  this.name = name;
95
98
  this.#eventSrc = eventSrc;
package/dist/cjs/index.js CHANGED
@@ -25,6 +25,7 @@ __export(index_exports, {
25
25
  ScriptingObject: () => import_scriptingObject.ScriptingObject,
26
26
  ScriptingObjectManager: () => import_scriptingObjectManager.ScriptingObjectManager,
27
27
  ScriptingObjectProxy: () => import_proxy.ScriptingObjectProxy,
28
+ SecurityContext: () => import_scriptingObjectManager.SecurityContext,
28
29
  getEventId: () => import_event.getEventId,
29
30
  isPublicFunction: () => import_scriptingObject.isPublicFunction,
30
31
  isScriptingObjectProxy: () => import_proxy.isScriptingObjectProxy,
@@ -29,9 +29,10 @@ const EXCEPTION_MESSAGE_TYPE = "elli:remoting:exception";
29
29
  const createMessage = ({
30
30
  messageType,
31
31
  messageBody,
32
+ requestId,
32
33
  onewayMsg = false
33
34
  }) => ({
34
- requestId: !onewayMsg ? (0, import_uuid.v4)() : null,
35
+ requestId: requestId ?? (!onewayMsg ? (0, import_uuid.v4)() : null),
35
36
  source: MESSAGE_SOURCE,
36
37
  type: messageType,
37
38
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -57,6 +58,10 @@ class Remoting {
57
58
  * The handle to the timeout monitor
58
59
  */
59
60
  #timeoutMonitorHandle = null;
61
+ /**
62
+ * The window that remoting was initialized on
63
+ */
64
+ #initializedWindow = null;
60
65
  /**
61
66
  * The set of windows that are allowed to send messages to this window
62
67
  */
@@ -72,53 +77,45 @@ class Remoting {
72
77
  this.#correlationId = correlationId;
73
78
  this.#logger = logger;
74
79
  }
75
- // Evaluates the timeouts on any waiting invocations
80
+ // Evaluates the timeouts on any waiting invocations and schedules the next check
76
81
  #evaluateTimeouts = () => {
82
+ this.#timeoutMonitorHandle = null;
77
83
  const ts = Date.now();
78
84
  const canceledItems = [];
85
+ let nextCancelTime = null;
79
86
  this.#invocations.forEach((eventData, key) => {
80
87
  const { requestId, cancelTime } = eventData;
81
- this.#logger.debug(
82
- `Checking response timeout for requestId: ${requestId}) @ ${cancelTime ?? ""}`
83
- );
84
- if (eventData.cancelTime && eventData.cancelTime < ts) {
88
+ if (cancelTime && cancelTime <= ts) {
85
89
  this.#logger.debug(
86
90
  `Detected response timeout for requestId: ${requestId}...`
87
91
  );
88
92
  canceledItems.push(key);
89
- eventData.resolve();
90
- this.#logger.debug(
91
- `Aborted waiting for response to requestid: ${requestId})`
92
- );
93
+ eventData.resolve(void 0);
94
+ } else if (cancelTime) {
95
+ nextCancelTime = nextCancelTime === null ? cancelTime : Math.min(nextCancelTime, cancelTime);
93
96
  }
94
97
  });
95
98
  canceledItems.forEach((key) => {
96
- this.#logger.debug(
97
- `removing invocations with requestId ${key} from cache since response time has expired`
98
- );
99
99
  this.#invocations.delete(key);
100
100
  });
101
- if (this.#invocations.size === 0) {
102
- this.#logger.debug(`stopping response monitor`);
103
- this.#stopResponseMonitor();
101
+ if (nextCancelTime !== null) {
102
+ const delay = Math.max(nextCancelTime - Date.now(), 0);
103
+ this.#scheduleTimeoutCheck(delay);
104
104
  }
105
105
  };
106
- // Set a timer interval to catch any invocations that didn't respond in a timely manner
107
- #startResponseMonitor = () => {
108
- if (this.#timeoutMonitorHandle === null) {
109
- this.#logger.debug("Staring response timeout evaluator");
110
- this.#timeoutMonitorHandle = window.setInterval(
111
- this.#evaluateTimeouts,
112
- 200
113
- );
114
- }
106
+ // Schedule a timeout check after a delay
107
+ #scheduleTimeoutCheck = (delayMs) => {
108
+ if (this.#timeoutMonitorHandle !== null) return;
109
+ this.#timeoutMonitorHandle = window.setTimeout(
110
+ this.#evaluateTimeouts,
111
+ delayMs
112
+ );
115
113
  };
116
- // Stops the timeout monitor interval
114
+ // Stops the timeout monitor
117
115
  #stopResponseMonitor = () => {
118
116
  if (this.#timeoutMonitorHandle !== null) {
119
- window.clearInterval(this.#timeoutMonitorHandle);
117
+ window.clearTimeout(this.#timeoutMonitorHandle);
120
118
  this.#timeoutMonitorHandle = null;
121
- this.#logger.debug("Stopped response timeout evaluator");
122
119
  }
123
120
  };
124
121
  // Pops an invocation from the incovation list
@@ -182,14 +179,14 @@ class Remoting {
182
179
  };
183
180
  // Processes a message received thru the window's message event
184
181
  #processMessage = (message) => {
185
- this.#logger.debug(
186
- `Remoting: Received message ${JSON.stringify(message.data)}`
187
- );
188
182
  if (this.#allowedSenders.size === 0) return false;
189
183
  if (!message.source) return false;
190
184
  const senderOrigin = this.#allowedSenders.get(message.source);
191
185
  if (!senderOrigin) return false;
192
186
  if (message?.data?.source !== MESSAGE_SOURCE) return false;
187
+ this.#logger.debug(
188
+ `Remoting: Received message of type "${message.data.type}"`
189
+ );
193
190
  if (message.data.type === RESPONSE_MESSAGE_TYPE)
194
191
  this.#processResponse(message.data);
195
192
  else if (message.data.type === EXCEPTION_MESSAGE_TYPE)
@@ -217,15 +214,28 @@ class Remoting {
217
214
  * @param win The window to initialize remoting for
218
215
  */
219
216
  initialize = (win) => {
220
- win.removeEventListener("message", this.#processMessage);
217
+ if (this.#initializedWindow) {
218
+ this.#initializedWindow.removeEventListener(
219
+ "message",
220
+ this.#processMessage
221
+ );
222
+ }
221
223
  win.addEventListener("message", this.#processMessage);
224
+ this.#initializedWindow = win;
222
225
  this.#logger.debug(`initialized remoting id: ${this.#correlationId}`);
223
226
  };
224
227
  /**
225
228
  * Closes the remoting service for a window
226
229
  */
227
230
  close = () => {
228
- window.removeEventListener("message", this.#processMessage);
231
+ if (this.#initializedWindow) {
232
+ this.#initializedWindow.removeEventListener(
233
+ "message",
234
+ this.#processMessage
235
+ );
236
+ this.#initializedWindow = null;
237
+ }
238
+ this.#stopResponseMonitor();
229
239
  this.#logger.debug(`closed remoting id: ${this.#correlationId}`);
230
240
  };
231
241
  /**
@@ -247,7 +257,7 @@ class Remoting {
247
257
  requestId: msg.requestId,
248
258
  resolve,
249
259
  reject,
250
- cancelTime: responseTimeoutMs ? Date.now() + Number.parseInt(responseTimeoutMs, 10) : null
260
+ cancelTime: responseTimeoutMs ? Date.now() + responseTimeoutMs : null
251
261
  });
252
262
  targetWin.postMessage(msg, targetOrigin);
253
263
  const { requestId } = msg;
@@ -256,9 +266,9 @@ class Remoting {
256
266
  );
257
267
  if (responseTimeoutMs) {
258
268
  this.#logger.debug(
259
- `starting response monitor for requestId: ${requestId || ""} for ${responseTimeoutMs} ms`
269
+ `scheduling timeout check for requestId: ${requestId || ""} in ${responseTimeoutMs} ms`
260
270
  );
261
- this.#startResponseMonitor();
271
+ this.#scheduleTimeoutCheck(responseTimeoutMs);
262
272
  }
263
273
  });
264
274
  };
@@ -272,6 +282,19 @@ class Remoting {
272
282
  items.push(callback);
273
283
  this.#listeners.set(messageType, items);
274
284
  };
285
+ /**
286
+ * Remove a previously registered callback for a specific message type
287
+ * @param {ListenParam<T>} param The parameters identifying the listener to remove
288
+ */
289
+ unlisten = (param) => {
290
+ const { messageType, callback } = param;
291
+ const items = this.#listeners.get(messageType);
292
+ if (!items) return;
293
+ const index = items.indexOf(callback);
294
+ if (index !== -1) {
295
+ items.splice(index, 1);
296
+ }
297
+ };
275
298
  /**
276
299
  * Send a message without any form of response. Fire and forget
277
300
  * @param {SendParam} param The parameters for the send
@@ -302,9 +325,9 @@ class Remoting {
302
325
  const { targetWin, targetOrigin, requestId, response } = param;
303
326
  const msg = createMessage({
304
327
  messageType: RESPONSE_MESSAGE_TYPE,
305
- messageBody: response
328
+ messageBody: response,
329
+ requestId
306
330
  });
307
- msg.requestId = requestId;
308
331
  targetWin.postMessage(msg, targetOrigin);
309
332
  this.#logger.debug(
310
333
  `Response sent to caller for invocation requestId: ${requestId}`
@@ -316,11 +339,12 @@ class Remoting {
316
339
  */
317
340
  raiseException = (param) => {
318
341
  const { targetWin, targetOrigin, requestId, ex } = param;
342
+ const messageBody = ex instanceof Error ? ex.message : ex;
319
343
  const msg = createMessage({
320
344
  messageType: EXCEPTION_MESSAGE_TYPE,
321
- messageBody: ex
345
+ messageBody,
346
+ requestId
322
347
  });
323
- msg.requestId = requestId;
324
348
  targetWin.postMessage(msg, targetOrigin);
325
349
  this.#logger.debug(
326
350
  `Exception sent to caller for invocation. requestId: ${requestId}`
@@ -30,6 +30,7 @@ var SecurityContext = /* @__PURE__ */ ((SecurityContext2) => {
30
30
  return SecurityContext2;
31
31
  })(SecurityContext || {});
32
32
  class ScriptingObjectManager {
33
+ #normalizeId = (id) => id.trim().toLowerCase();
33
34
  /**
34
35
  * collection of registered scripting objects
35
36
  */
@@ -40,7 +41,7 @@ class ScriptingObjectManager {
40
41
  #guestScriptingObjects = /* @__PURE__ */ new Map();
41
42
  #addGuestScriptingObject = (params) => {
42
43
  const { so, guestId } = params;
43
- const objectId = so.id.toLowerCase();
44
+ const objectId = this.#normalizeId(so.id);
44
45
  const guestSOs = this.#guestScriptingObjects.get(guestId);
45
46
  if (!guestSOs) {
46
47
  this.#guestScriptingObjects.set(guestId, /* @__PURE__ */ new Map([[objectId, params]]));
@@ -54,7 +55,10 @@ class ScriptingObjectManager {
54
55
  };
55
56
  #disposeSO = ({ so }) => {
56
57
  if (so._dispose && typeof so._dispose === "function") {
57
- so._dispose();
58
+ try {
59
+ so._dispose();
60
+ } catch {
61
+ }
58
62
  }
59
63
  };
60
64
  /**
@@ -119,8 +123,8 @@ class ScriptingObjectManager {
119
123
  if (!so?.id || !so?._toJSON) {
120
124
  throw new Error("Object is not derived from ScriptingObject");
121
125
  }
122
- const objectId = so.id.toLowerCase();
123
- if (objectId.trim().toLowerCase() === MODULE_OBJECT && !guestId) {
126
+ const objectId = this.#normalizeId(so.id);
127
+ if (objectId === MODULE_OBJECT && !guestId) {
124
128
  throw new Error(`Guest id is required to add Module scripting object`);
125
129
  }
126
130
  if (guestId) {
@@ -138,7 +142,7 @@ class ScriptingObjectManager {
138
142
  * @returns proxied scripting object reference
139
143
  */
140
144
  getObject = (objectId, guest) => {
141
- const id = objectId.trim().toLowerCase();
145
+ const id = this.#normalizeId(objectId);
142
146
  let soInfo = this.#getGuestScriptingObject({
143
147
  objectId: id,
144
148
  guestId: guest?.id
@@ -161,10 +165,12 @@ class ScriptingObjectManager {
161
165
  * @returns name of scripting objects for the given guest
162
166
  */
163
167
  listScriptingObjects = (guestId) => {
164
- let objects = Array.from(this.#scriptingObjects.keys());
168
+ const objects = new Set(this.#scriptingObjects.keys());
165
169
  const guestSOs = this.#guestScriptingObjects.get(guestId);
166
- objects = guestSOs ? objects.concat(Array.from(guestSOs.keys())) : objects;
167
- return Array.from(new Set(objects));
170
+ if (guestSOs) {
171
+ for (const key of guestSOs.keys()) objects.add(key);
172
+ }
173
+ return Array.from(objects);
168
174
  };
169
175
  /**
170
176
  * removes scripting object
@@ -172,7 +178,7 @@ class ScriptingObjectManager {
172
178
  * @param guestId unique id of the guest
173
179
  */
174
180
  removeScriptingObject = (objectId, guestId) => {
175
- const id = objectId.toLowerCase();
181
+ const id = this.#normalizeId(objectId);
176
182
  if (guestId) {
177
183
  this.#removeGuestScriptingObject({ objectId: id, guestId });
178
184
  } else {
package/dist/esm/event.js CHANGED
@@ -32,9 +32,9 @@ class ProxyEvent {
32
32
  * @returns true if given object is an instance of ProxyEvent
33
33
  */
34
34
  static [Symbol.hasInstance](obj) {
35
- return obj.getType?.() === "ProxyEvent";
35
+ return typeof obj === "object" && obj !== null && "getType" in obj && typeof obj.getType === "function" && obj.getType() === "ProxyEvent";
36
36
  }
37
- /* eslint-enbale indent */
37
+ /* eslint-enable indent */
38
38
  /**
39
39
  * module that owns this event management. SSF Guest or App Bridge host
40
40
  */
@@ -64,6 +64,9 @@ class ProxyEvent {
64
64
  */
65
65
  constructor(param) {
66
66
  const { name, objectId, eventSrc } = param;
67
+ if (!name) throw new Error("Event name is required");
68
+ if (!objectId) throw new Error("Scripting object id is required");
69
+ if (!eventSrc) throw new Error("Event source is required");
67
70
  this.objectId = objectId;
68
71
  this.name = name;
69
72
  this.#eventSrc = eventSrc;
package/dist/esm/index.js CHANGED
@@ -3,7 +3,10 @@ import { getEventId, ProxyEvent } from "./event.js";
3
3
  import { Event } from "./event.js";
4
4
  import { ScriptingObject, isPublicFunction } from "./scriptingObject.js";
5
5
  import { MessageType } from "./messageType.js";
6
- import { ScriptingObjectManager } from "./scriptingObjectManager.js";
6
+ import {
7
+ ScriptingObjectManager,
8
+ SecurityContext
9
+ } from "./scriptingObjectManager.js";
7
10
  import { ScriptingObjectProxy, isScriptingObjectProxy } from "./proxy.js";
8
11
  export {
9
12
  Event,
@@ -13,6 +16,7 @@ export {
13
16
  ScriptingObject,
14
17
  ScriptingObjectManager,
15
18
  ScriptingObjectProxy,
19
+ SecurityContext,
16
20
  getEventId,
17
21
  isPublicFunction,
18
22
  isScriptingObjectProxy,
@@ -5,9 +5,10 @@ const EXCEPTION_MESSAGE_TYPE = "elli:remoting:exception";
5
5
  const createMessage = ({
6
6
  messageType,
7
7
  messageBody,
8
+ requestId,
8
9
  onewayMsg = false
9
10
  }) => ({
10
- requestId: !onewayMsg ? uuidv4() : null,
11
+ requestId: requestId ?? (!onewayMsg ? uuidv4() : null),
11
12
  source: MESSAGE_SOURCE,
12
13
  type: messageType,
13
14
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -33,6 +34,10 @@ class Remoting {
33
34
  * The handle to the timeout monitor
34
35
  */
35
36
  #timeoutMonitorHandle = null;
37
+ /**
38
+ * The window that remoting was initialized on
39
+ */
40
+ #initializedWindow = null;
36
41
  /**
37
42
  * The set of windows that are allowed to send messages to this window
38
43
  */
@@ -48,53 +53,45 @@ class Remoting {
48
53
  this.#correlationId = correlationId;
49
54
  this.#logger = logger;
50
55
  }
51
- // Evaluates the timeouts on any waiting invocations
56
+ // Evaluates the timeouts on any waiting invocations and schedules the next check
52
57
  #evaluateTimeouts = () => {
58
+ this.#timeoutMonitorHandle = null;
53
59
  const ts = Date.now();
54
60
  const canceledItems = [];
61
+ let nextCancelTime = null;
55
62
  this.#invocations.forEach((eventData, key) => {
56
63
  const { requestId, cancelTime } = eventData;
57
- this.#logger.debug(
58
- `Checking response timeout for requestId: ${requestId}) @ ${cancelTime ?? ""}`
59
- );
60
- if (eventData.cancelTime && eventData.cancelTime < ts) {
64
+ if (cancelTime && cancelTime <= ts) {
61
65
  this.#logger.debug(
62
66
  `Detected response timeout for requestId: ${requestId}...`
63
67
  );
64
68
  canceledItems.push(key);
65
- eventData.resolve();
66
- this.#logger.debug(
67
- `Aborted waiting for response to requestid: ${requestId})`
68
- );
69
+ eventData.resolve(void 0);
70
+ } else if (cancelTime) {
71
+ nextCancelTime = nextCancelTime === null ? cancelTime : Math.min(nextCancelTime, cancelTime);
69
72
  }
70
73
  });
71
74
  canceledItems.forEach((key) => {
72
- this.#logger.debug(
73
- `removing invocations with requestId ${key} from cache since response time has expired`
74
- );
75
75
  this.#invocations.delete(key);
76
76
  });
77
- if (this.#invocations.size === 0) {
78
- this.#logger.debug(`stopping response monitor`);
79
- this.#stopResponseMonitor();
77
+ if (nextCancelTime !== null) {
78
+ const delay = Math.max(nextCancelTime - Date.now(), 0);
79
+ this.#scheduleTimeoutCheck(delay);
80
80
  }
81
81
  };
82
- // Set a timer interval to catch any invocations that didn't respond in a timely manner
83
- #startResponseMonitor = () => {
84
- if (this.#timeoutMonitorHandle === null) {
85
- this.#logger.debug("Staring response timeout evaluator");
86
- this.#timeoutMonitorHandle = window.setInterval(
87
- this.#evaluateTimeouts,
88
- 200
89
- );
90
- }
82
+ // Schedule a timeout check after a delay
83
+ #scheduleTimeoutCheck = (delayMs) => {
84
+ if (this.#timeoutMonitorHandle !== null) return;
85
+ this.#timeoutMonitorHandle = window.setTimeout(
86
+ this.#evaluateTimeouts,
87
+ delayMs
88
+ );
91
89
  };
92
- // Stops the timeout monitor interval
90
+ // Stops the timeout monitor
93
91
  #stopResponseMonitor = () => {
94
92
  if (this.#timeoutMonitorHandle !== null) {
95
- window.clearInterval(this.#timeoutMonitorHandle);
93
+ window.clearTimeout(this.#timeoutMonitorHandle);
96
94
  this.#timeoutMonitorHandle = null;
97
- this.#logger.debug("Stopped response timeout evaluator");
98
95
  }
99
96
  };
100
97
  // Pops an invocation from the incovation list
@@ -158,14 +155,14 @@ class Remoting {
158
155
  };
159
156
  // Processes a message received thru the window's message event
160
157
  #processMessage = (message) => {
161
- this.#logger.debug(
162
- `Remoting: Received message ${JSON.stringify(message.data)}`
163
- );
164
158
  if (this.#allowedSenders.size === 0) return false;
165
159
  if (!message.source) return false;
166
160
  const senderOrigin = this.#allowedSenders.get(message.source);
167
161
  if (!senderOrigin) return false;
168
162
  if (message?.data?.source !== MESSAGE_SOURCE) return false;
163
+ this.#logger.debug(
164
+ `Remoting: Received message of type "${message.data.type}"`
165
+ );
169
166
  if (message.data.type === RESPONSE_MESSAGE_TYPE)
170
167
  this.#processResponse(message.data);
171
168
  else if (message.data.type === EXCEPTION_MESSAGE_TYPE)
@@ -193,15 +190,28 @@ class Remoting {
193
190
  * @param win The window to initialize remoting for
194
191
  */
195
192
  initialize = (win) => {
196
- win.removeEventListener("message", this.#processMessage);
193
+ if (this.#initializedWindow) {
194
+ this.#initializedWindow.removeEventListener(
195
+ "message",
196
+ this.#processMessage
197
+ );
198
+ }
197
199
  win.addEventListener("message", this.#processMessage);
200
+ this.#initializedWindow = win;
198
201
  this.#logger.debug(`initialized remoting id: ${this.#correlationId}`);
199
202
  };
200
203
  /**
201
204
  * Closes the remoting service for a window
202
205
  */
203
206
  close = () => {
204
- window.removeEventListener("message", this.#processMessage);
207
+ if (this.#initializedWindow) {
208
+ this.#initializedWindow.removeEventListener(
209
+ "message",
210
+ this.#processMessage
211
+ );
212
+ this.#initializedWindow = null;
213
+ }
214
+ this.#stopResponseMonitor();
205
215
  this.#logger.debug(`closed remoting id: ${this.#correlationId}`);
206
216
  };
207
217
  /**
@@ -223,7 +233,7 @@ class Remoting {
223
233
  requestId: msg.requestId,
224
234
  resolve,
225
235
  reject,
226
- cancelTime: responseTimeoutMs ? Date.now() + Number.parseInt(responseTimeoutMs, 10) : null
236
+ cancelTime: responseTimeoutMs ? Date.now() + responseTimeoutMs : null
227
237
  });
228
238
  targetWin.postMessage(msg, targetOrigin);
229
239
  const { requestId } = msg;
@@ -232,9 +242,9 @@ class Remoting {
232
242
  );
233
243
  if (responseTimeoutMs) {
234
244
  this.#logger.debug(
235
- `starting response monitor for requestId: ${requestId || ""} for ${responseTimeoutMs} ms`
245
+ `scheduling timeout check for requestId: ${requestId || ""} in ${responseTimeoutMs} ms`
236
246
  );
237
- this.#startResponseMonitor();
247
+ this.#scheduleTimeoutCheck(responseTimeoutMs);
238
248
  }
239
249
  });
240
250
  };
@@ -248,6 +258,19 @@ class Remoting {
248
258
  items.push(callback);
249
259
  this.#listeners.set(messageType, items);
250
260
  };
261
+ /**
262
+ * Remove a previously registered callback for a specific message type
263
+ * @param {ListenParam<T>} param The parameters identifying the listener to remove
264
+ */
265
+ unlisten = (param) => {
266
+ const { messageType, callback } = param;
267
+ const items = this.#listeners.get(messageType);
268
+ if (!items) return;
269
+ const index = items.indexOf(callback);
270
+ if (index !== -1) {
271
+ items.splice(index, 1);
272
+ }
273
+ };
251
274
  /**
252
275
  * Send a message without any form of response. Fire and forget
253
276
  * @param {SendParam} param The parameters for the send
@@ -278,9 +301,9 @@ class Remoting {
278
301
  const { targetWin, targetOrigin, requestId, response } = param;
279
302
  const msg = createMessage({
280
303
  messageType: RESPONSE_MESSAGE_TYPE,
281
- messageBody: response
304
+ messageBody: response,
305
+ requestId
282
306
  });
283
- msg.requestId = requestId;
284
307
  targetWin.postMessage(msg, targetOrigin);
285
308
  this.#logger.debug(
286
309
  `Response sent to caller for invocation requestId: ${requestId}`
@@ -292,11 +315,12 @@ class Remoting {
292
315
  */
293
316
  raiseException = (param) => {
294
317
  const { targetWin, targetOrigin, requestId, ex } = param;
318
+ const messageBody = ex instanceof Error ? ex.message : ex;
295
319
  const msg = createMessage({
296
320
  messageType: EXCEPTION_MESSAGE_TYPE,
297
- messageBody: ex
321
+ messageBody,
322
+ requestId
298
323
  });
299
- msg.requestId = requestId;
300
324
  targetWin.postMessage(msg, targetOrigin);
301
325
  this.#logger.debug(
302
326
  `Exception sent to caller for invocation. requestId: ${requestId}`
@@ -5,6 +5,7 @@ var SecurityContext = /* @__PURE__ */ ((SecurityContext2) => {
5
5
  return SecurityContext2;
6
6
  })(SecurityContext || {});
7
7
  class ScriptingObjectManager {
8
+ #normalizeId = (id) => id.trim().toLowerCase();
8
9
  /**
9
10
  * collection of registered scripting objects
10
11
  */
@@ -15,7 +16,7 @@ class ScriptingObjectManager {
15
16
  #guestScriptingObjects = /* @__PURE__ */ new Map();
16
17
  #addGuestScriptingObject = (params) => {
17
18
  const { so, guestId } = params;
18
- const objectId = so.id.toLowerCase();
19
+ const objectId = this.#normalizeId(so.id);
19
20
  const guestSOs = this.#guestScriptingObjects.get(guestId);
20
21
  if (!guestSOs) {
21
22
  this.#guestScriptingObjects.set(guestId, /* @__PURE__ */ new Map([[objectId, params]]));
@@ -29,7 +30,10 @@ class ScriptingObjectManager {
29
30
  };
30
31
  #disposeSO = ({ so }) => {
31
32
  if (so._dispose && typeof so._dispose === "function") {
32
- so._dispose();
33
+ try {
34
+ so._dispose();
35
+ } catch {
36
+ }
33
37
  }
34
38
  };
35
39
  /**
@@ -94,8 +98,8 @@ class ScriptingObjectManager {
94
98
  if (!so?.id || !so?._toJSON) {
95
99
  throw new Error("Object is not derived from ScriptingObject");
96
100
  }
97
- const objectId = so.id.toLowerCase();
98
- if (objectId.trim().toLowerCase() === MODULE_OBJECT && !guestId) {
101
+ const objectId = this.#normalizeId(so.id);
102
+ if (objectId === MODULE_OBJECT && !guestId) {
99
103
  throw new Error(`Guest id is required to add Module scripting object`);
100
104
  }
101
105
  if (guestId) {
@@ -113,7 +117,7 @@ class ScriptingObjectManager {
113
117
  * @returns proxied scripting object reference
114
118
  */
115
119
  getObject = (objectId, guest) => {
116
- const id = objectId.trim().toLowerCase();
120
+ const id = this.#normalizeId(objectId);
117
121
  let soInfo = this.#getGuestScriptingObject({
118
122
  objectId: id,
119
123
  guestId: guest?.id
@@ -136,10 +140,12 @@ class ScriptingObjectManager {
136
140
  * @returns name of scripting objects for the given guest
137
141
  */
138
142
  listScriptingObjects = (guestId) => {
139
- let objects = Array.from(this.#scriptingObjects.keys());
143
+ const objects = new Set(this.#scriptingObjects.keys());
140
144
  const guestSOs = this.#guestScriptingObjects.get(guestId);
141
- objects = guestSOs ? objects.concat(Array.from(guestSOs.keys())) : objects;
142
- return Array.from(new Set(objects));
145
+ if (guestSOs) {
146
+ for (const key of guestSOs.keys()) objects.add(key);
147
+ }
148
+ return Array.from(objects);
143
149
  };
144
150
  /**
145
151
  * removes scripting object
@@ -147,7 +153,7 @@ class ScriptingObjectManager {
147
153
  * @param guestId unique id of the guest
148
154
  */
149
155
  removeScriptingObject = (objectId, guestId) => {
150
- const id = objectId.toLowerCase();
156
+ const id = this.#normalizeId(objectId);
151
157
  if (guestId) {
152
158
  this.#removeGuestScriptingObject({ objectId: id, guestId });
153
159
  } else {
@@ -143,7 +143,7 @@ export declare class ProxyEvent<AppEvents extends EventListeners = Events> imple
143
143
  * @param obj object to be compared
144
144
  * @returns true if given object is an instance of ProxyEvent
145
145
  */
146
- static [Symbol.hasInstance](obj: ProxyEvent): boolean;
146
+ static [Symbol.hasInstance](obj: unknown): boolean;
147
147
  /**
148
148
  * unique id of scripting object
149
149
  */
@@ -2,7 +2,7 @@ import { ScriptingObjectTypes, Events } from '@elliemae/pui-scripting-object';
2
2
  import { LogLevels } from '@elliemae/pui-diagnostics';
3
3
  import { EventListeners } from './common.js';
4
4
  import { IEventManager } from './event.js';
5
- import { ScriptingObjects } from './scriptingObjectManager.js';
5
+ import { ScriptingObjects } from './scriptingObject.js';
6
6
  /**
7
7
  * parameters for connecting to the host
8
8
  */
@@ -11,7 +11,7 @@ export type ConnectParam = {
11
11
  * reference to the guest window
12
12
  */
13
13
  window?: Window;
14
- } & Record<string, any>;
14
+ } & Record<string, unknown>;
15
15
  /**
16
16
  * Interface for SSF guest
17
17
  */
@@ -46,7 +46,7 @@ export interface ISSFGuest<AppObjects extends ScriptingObjects = Partial<Scripti
46
46
  * Get names of scripting objects exposed by the host
47
47
  * @returns scripting objects exposed by the host
48
48
  */
49
- listObjects: () => Promise<keyof AppObjects>;
49
+ listObjects: () => Promise<Array<Extract<keyof AppObjects, string>>>;
50
50
  /**
51
51
  * remove the guest from the host
52
52
  */