@salesforce/experimental-mfe-bridge 2.2.1-rc.2 → 2.2.1-rc.8

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 (2) hide show
  1. package/dist/index.esm.js +61 -19
  2. package/package.json +4 -2
package/dist/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @salesforce/experimental-mfe-bridge v2.2.1-rc.2 (2026-04-10) */
1
+ /*! @salesforce/experimental-mfe-bridge v2.2.1-rc.8 (2026-06-16) */
2
2
  /**
3
3
  * EmbeddingResizer - Handles dynamic iframe/container resizing
4
4
  * Uses ResizeObserver to monitor element size changes and notify the host
@@ -119,6 +119,15 @@ class EmbeddingResizer {
119
119
  * Auto-handles theme synchronization and error telemetry
120
120
  */
121
121
  const GRAPHQL_TIMEOUT_MS = 30_000;
122
+ /** Parses `value` as a URL and returns its `.origin`, or `null` if it does not parse. */
123
+ function extractOrigin(value) {
124
+ try {
125
+ return new URL(value).origin;
126
+ }
127
+ catch {
128
+ return null;
129
+ }
130
+ }
122
131
  class ExternalEmbedBridge extends EventTarget {
123
132
  #connected = false;
124
133
  #hostAppOrigin = null;
@@ -130,6 +139,14 @@ class ExternalEmbedBridge extends EventTarget {
130
139
  #graphqlCounter = 0;
131
140
  constructor() {
132
141
  super();
142
+ // Abort init if hostMetaData is missing/invalid — widget surfaces a clear failure
143
+ // instead of running half-initialised.
144
+ const failures = this.#readMetadataFromUrl();
145
+ if (failures.length > 0) {
146
+ // eslint-disable-next-line no-console
147
+ console.error("[Bridge] Bridge could not be established:\n - " + failures.join("\n - "));
148
+ return;
149
+ }
133
150
  window.addEventListener("message", (e) => this.#handleHostMessage(e));
134
151
  this.#setupErrorCapture();
135
152
  this.#sendToHost("bridge-ready");
@@ -137,16 +154,44 @@ class ExternalEmbedBridge extends EventTarget {
137
154
  // eslint-disable-next-line no-console
138
155
  console.log("[Bridge] Initialized and ready for communication");
139
156
  }
157
+ /** Populates #instanceId and #hostAppOrigin from the iframe URL's `hostMetaData`
158
+ * query param. Returns failure reasons (empty = success). */
159
+ #readMetadataFromUrl() {
160
+ const raw = new URLSearchParams(window.location.search).get("hostMetaData");
161
+ if (!raw)
162
+ return ["`hostMetaData` query param is missing"];
163
+ let parsed;
164
+ try {
165
+ parsed = JSON.parse(raw);
166
+ }
167
+ catch (e) {
168
+ const message = e instanceof Error ? e.message : String(e);
169
+ return [`\`hostMetaData\` is not valid JSON: ${message}`];
170
+ }
171
+ const instanceId = typeof parsed?.instanceId === "string" ? parsed.instanceId : "";
172
+ const rawHostAppOrigin = typeof parsed?.hostAppOrigin === "string" ? parsed.hostAppOrigin : "";
173
+ const hostAppOrigin = rawHostAppOrigin ? extractOrigin(rawHostAppOrigin) : "";
174
+ const failures = [];
175
+ if (!instanceId)
176
+ failures.push("`instanceId` is missing or empty");
177
+ if (!rawHostAppOrigin) {
178
+ failures.push("`hostAppOrigin` is missing or empty");
179
+ }
180
+ else if (!hostAppOrigin) {
181
+ failures.push("`hostAppOrigin` is not a valid URL");
182
+ }
183
+ if (failures.length === 0) {
184
+ this.#instanceId = instanceId;
185
+ this.#hostAppOrigin = hostAppOrigin;
186
+ }
187
+ return failures;
188
+ }
140
189
  #handleHostMessage(event) {
141
- if (event.source !== window.parent)
142
- return;
143
- if (this.#hostAppOrigin && event.origin !== this.#hostAppOrigin)
190
+ if (event.source !== window.parent || event.origin !== this.#hostAppOrigin)
144
191
  return;
145
192
  const payload = event.data || {};
146
193
  const { type, data, id } = payload;
147
- if (typeof type !== "string" || !type.startsWith("salesforce-"))
148
- return;
149
- if (this.#instanceId && id !== this.#instanceId)
194
+ if (typeof type !== "string" || !type.startsWith("salesforce-") || id !== this.#instanceId)
150
195
  return;
151
196
  // eslint-disable-next-line no-console
152
197
  console.log("[Bridge] host->widget", type, data);
@@ -158,7 +203,7 @@ class ExternalEmbedBridge extends EventTarget {
158
203
  this.#handleDataUpdate(data);
159
204
  break;
160
205
  case "salesforce-shell-ready":
161
- this.#handleConnectionReady(event.origin, id);
206
+ this.#handleConnectionReady();
162
207
  break;
163
208
  case "salesforce-bridge-graphql-response":
164
209
  this.#handleGraphQLResponse(data);
@@ -176,10 +221,8 @@ class ExternalEmbedBridge extends EventTarget {
176
221
  // use super to escape the override
177
222
  super.dispatchEvent(new CustomEvent("data", { detail: payload }));
178
223
  }
179
- #handleConnectionReady(origin, id) {
224
+ #handleConnectionReady() {
180
225
  this.#connected = true;
181
- this.#hostAppOrigin = origin;
182
- this.#instanceId = id;
183
226
  // use super to escape the override
184
227
  super.dispatchEvent(new CustomEvent("connected"));
185
228
  }
@@ -231,18 +274,12 @@ class ExternalEmbedBridge extends EventTarget {
231
274
  });
232
275
  this.#resizer.start();
233
276
  }
234
- #getHostAppOrigin(type) {
235
- return this.#hostAppOrigin || (type === "bridge-ready" ? "*" : null);
236
- }
237
277
  #sendToHost(type, data) {
238
- const origin = this.#getHostAppOrigin(type);
239
- if (!origin)
240
- return;
241
278
  try {
242
- const message = this.#instanceId ? { type, data, id: this.#instanceId } : { type, data };
279
+ const message = { type, data, id: this.#instanceId };
243
280
  // eslint-disable-next-line no-console
244
281
  console.log("[Bridge] Sending message to host:", message);
245
- window.parent.postMessage(message, origin);
282
+ window.parent.postMessage(message, this.#hostAppOrigin);
246
283
  }
247
284
  catch (error) {
248
285
  // eslint-disable-next-line no-console
@@ -284,6 +321,11 @@ class ExternalEmbedBridge extends EventTarget {
284
321
  // Override dispatchEvent to forward custom events to the host via post message
285
322
  dispatchEvent(event) {
286
323
  const result = super.dispatchEvent(event);
324
+ if (!this.#connected) {
325
+ // eslint-disable-next-line no-console
326
+ console.warn("[Bridge] dispatchEvent: bridge not connected, dropping", event.type);
327
+ return result;
328
+ }
287
329
  this.#sendToHost("custom-event", {
288
330
  eventType: event.type,
289
331
  detail: event.detail,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/experimental-mfe-bridge",
3
- "version": "2.2.1-rc.2",
3
+ "version": "2.2.1-rc.8",
4
4
  "private": false,
5
5
  "description": "EventTarget-Based Embed ↔ Host Communication for UI Embedding",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -25,10 +25,12 @@
25
25
  "clean": "rimraf dist"
26
26
  },
27
27
  "devDependencies": {
28
- "utils": "2.2.1-rc.2"
28
+ "utils": "2.2.1-rc.8"
29
29
  },
30
30
  "files": [
31
31
  "dist/",
32
+ "!dist/__tests__/",
33
+ "!dist/__mocks__/",
32
34
  "!dist/*.test.js",
33
35
  "!dist/*.map",
34
36
  "README.md",