@salesforce/experimental-mfe-lwc-shell 2.2.0 → 2.2.1-rc.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.
@@ -40,8 +40,7 @@ export declare class InternalHostLwcShell extends HTMLElement {
40
40
  private _title;
41
41
  private _view;
42
42
  private _debugEnabled;
43
- private _pendingGraphQLCount;
44
- private static readonly MAX_CONCURRENT_GRAPHQL;
43
+ private _graphqlHandler;
45
44
  static get observedAttributes(): string[];
46
45
  constructor();
47
46
  connectedCallback(): void;
@@ -83,7 +82,6 @@ export declare class InternalHostLwcShell extends HTMLElement {
83
82
  private _exitFullscreen;
84
83
  private _handleBridgeReady;
85
84
  private _handleBridgeError;
86
- private _handleGraphQLRequest;
87
85
  private _handleContainerClick;
88
86
  private _applySandbox;
89
87
  private _computeSandboxTokens;
@@ -0,0 +1,29 @@
1
+ export interface GraphQLBridgeRequest {
2
+ requestId: string;
3
+ query: string;
4
+ variables?: Record<string, unknown>;
5
+ }
6
+ export interface GraphQLBridgeResponse {
7
+ requestId: string;
8
+ ok: boolean;
9
+ result?: {
10
+ data: unknown;
11
+ errors?: unknown[];
12
+ };
13
+ error?: {
14
+ message: string;
15
+ };
16
+ }
17
+ export declare function executeGraphQL(query: string, variables?: Record<string, unknown>): Promise<{
18
+ data: unknown;
19
+ errors?: unknown[];
20
+ }>;
21
+ export declare class GraphQLBridgeHandler {
22
+ #private;
23
+ constructor(sendResponse: (data: GraphQLBridgeResponse) => void, maxConcurrent?: number, maxQueueSize?: number);
24
+ static isValidRequest(data: unknown): data is GraphQLBridgeRequest;
25
+ rejectInvalidRequest(data: unknown): void;
26
+ handleRequest({ requestId, query, variables }: GraphQLBridgeRequest): Promise<void>;
27
+ reset(): void;
28
+ }
29
+ //# sourceMappingURL=graphqlBridgeHandler.d.ts.map
package/dist/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! @salesforce/experimental-mfe-lwc-shell v2.2.0-rc.2 (2026-03-20) */
1
+ /*! @salesforce/experimental-mfe-lwc-shell v2.2.1-rc.0 (2026-04-08) */
2
2
  import { gql, unstable_graphql_imperative } from 'lightning/graphql';
3
3
 
4
4
  /**
@@ -28,6 +28,108 @@ async function executeGraphQL(query, variables) {
28
28
  const result = await unstable_graphql_imperative({ query: documentNode, variables });
29
29
  return { data: result?.data, errors: result?.errors };
30
30
  }
31
+ class GraphQLBridgeHandler {
32
+ #sendResponse;
33
+ #pendingCount = 0;
34
+ #queue = [];
35
+ #maxConcurrent;
36
+ #maxQueueSize;
37
+ #generation = 0;
38
+ constructor(sendResponse, maxConcurrent = 10, maxQueueSize = 50) {
39
+ this.#sendResponse = sendResponse;
40
+ this.#maxConcurrent = maxConcurrent;
41
+ this.#maxQueueSize = maxQueueSize;
42
+ }
43
+ static isValidRequest(data) {
44
+ const req = data;
45
+ return (typeof req?.requestId === "string" &&
46
+ typeof req?.query === "string" &&
47
+ (req.variables == null || (typeof req.variables === "object" && !Array.isArray(req.variables))));
48
+ }
49
+ rejectInvalidRequest(data) {
50
+ const req = data;
51
+ if (typeof req?.requestId !== "string") {
52
+ this.#sendResponse({
53
+ requestId: req?.requestId,
54
+ ok: false,
55
+ error: { message: "Invalid GraphQL request data" },
56
+ });
57
+ return;
58
+ }
59
+ const { requestId, query, variables } = req;
60
+ if (typeof query !== "string") {
61
+ this.#sendResponse({
62
+ requestId: requestId,
63
+ ok: false,
64
+ error: { message: "Invalid GraphQL query: query must be a string" },
65
+ });
66
+ return;
67
+ }
68
+ if (variables != null && (typeof variables !== "object" || Array.isArray(variables))) {
69
+ this.#sendResponse({
70
+ requestId: requestId,
71
+ ok: false,
72
+ error: { message: "Invalid GraphQL variables: must be a plain object" },
73
+ });
74
+ }
75
+ }
76
+ handleRequest({ requestId, query, variables }) {
77
+ if (this.#pendingCount >= this.#maxConcurrent) {
78
+ return this.#enqueueRequest(requestId, query, variables);
79
+ }
80
+ return this.#execute(requestId, query, variables);
81
+ }
82
+ reset() {
83
+ this.#generation++;
84
+ this.#queue = [];
85
+ this.#pendingCount = 0;
86
+ }
87
+ #execute = async (requestId, query, variables) => {
88
+ const gen = this.#generation;
89
+ this.#pendingCount++;
90
+ try {
91
+ const result = await executeGraphQL(query, variables);
92
+ if (gen === this.#generation) {
93
+ this.#sendResponse({ requestId, ok: true, result });
94
+ }
95
+ }
96
+ catch (err) {
97
+ if (gen === this.#generation) {
98
+ this.#sendResponse({
99
+ requestId,
100
+ ok: false,
101
+ error: { message: err?.message || "GraphQL request failed" },
102
+ });
103
+ }
104
+ }
105
+ finally {
106
+ if (gen === this.#generation) {
107
+ this.#pendingCount--;
108
+ this.#processRequestQueue();
109
+ }
110
+ }
111
+ };
112
+ #enqueueRequest = (requestId, query, variables) => {
113
+ if (this.#queue.length >= this.#maxQueueSize) {
114
+ this.#sendResponse({
115
+ requestId,
116
+ ok: false,
117
+ error: { message: "Too many queued GraphQL requests" },
118
+ });
119
+ return Promise.resolve();
120
+ }
121
+ return new Promise((resolve) => {
122
+ this.#queue.push({ requestId, query, variables, done: resolve });
123
+ });
124
+ };
125
+ #processRequestQueue = () => {
126
+ if (this.#queue.length === 0 || this.#pendingCount >= this.#maxConcurrent) {
127
+ return;
128
+ }
129
+ const next = this.#queue.shift();
130
+ this.#execute(next.requestId, next.query, next.variables).then(next.done);
131
+ };
132
+ }
31
133
 
32
134
  /**
33
135
  * InternalHostLwcShell
@@ -51,6 +153,8 @@ async function executeGraphQL(query, variables) {
51
153
  *
52
154
  * See the README and the `productRegistration` demo for a full recipe.
53
155
  */
156
+ const MAX_CONCURRENT_GRAPHQL_REQUESTS = 10;
157
+ const MAX_GRAPHQL_QUEUE_SIZE = 50;
54
158
  const BASE_TOKENS = ["allow-scripts", "allow-pointer-lock"];
55
159
  const OPTIONAL_TOKENS = ["allow-downloads", "allow-forms", "allow-modals"];
56
160
  const BLOCKED_TOKENS = ["allow-same-origin", "allow-top-navigation", "allow-popups"];
@@ -147,14 +251,16 @@ class InternalHostLwcShell extends HTMLElement {
147
251
  _title = "Embedded widget";
148
252
  _view = "compact";
149
253
  _debugEnabled = true;
150
- _pendingGraphQLCount = 0;
151
- static MAX_CONCURRENT_GRAPHQL = 10;
254
+ _graphqlHandler;
152
255
  static get observedAttributes() {
153
256
  return ["src", "srcdoc", "sandbox", "title", "view", "debug"];
154
257
  }
155
258
  constructor() {
156
259
  super();
157
260
  this._shadow = this.attachShadow({ mode: "closed" });
261
+ this._graphqlHandler = new GraphQLBridgeHandler((data) => {
262
+ this._postToIframe("bridge-graphql-response", data);
263
+ }, MAX_CONCURRENT_GRAPHQL_REQUESTS, MAX_GRAPHQL_QUEUE_SIZE);
158
264
  }
159
265
  connectedCallback() {
160
266
  this._renderInitial();
@@ -163,6 +269,7 @@ class InternalHostLwcShell extends HTMLElement {
163
269
  }
164
270
  disconnectedCallback() {
165
271
  window.removeEventListener("message", this._handleMessage);
272
+ this._graphqlHandler.reset();
166
273
  if (this._readinessTimeout) {
167
274
  clearTimeout(this._readinessTimeout);
168
275
  this._readinessTimeout = null;
@@ -428,7 +535,12 @@ class InternalHostLwcShell extends HTMLElement {
428
535
  }
429
536
  }
430
537
  else if (type === "bridge-graphql-request") {
431
- this._handleGraphQLRequest(data);
538
+ if (GraphQLBridgeHandler.isValidRequest(data)) {
539
+ this._graphqlHandler.handleRequest(data);
540
+ }
541
+ else {
542
+ this._graphqlHandler.rejectInvalidRequest(data);
543
+ }
432
544
  }
433
545
  else if (type === "bridge-ready") {
434
546
  this._handleBridgeReady();
@@ -498,57 +610,6 @@ class InternalHostLwcShell extends HTMLElement {
498
610
  this.dispatchEvent(new CustomEvent("widget-bridge-error", { detail: errorData }));
499
611
  this._log("bridge-error", errorData);
500
612
  }
501
- async _handleGraphQLRequest(data) {
502
- if (typeof data?.requestId !== "string") {
503
- this._log("_handleGraphQLRequest: invalid request data", data);
504
- this._postToIframe("bridge-graphql-response", {
505
- requestId: data?.requestId,
506
- ok: false,
507
- error: { message: "Invalid GraphQL request data" },
508
- });
509
- return;
510
- }
511
- const { requestId, query, variables } = data;
512
- if (typeof query !== "string") {
513
- this._postToIframe("bridge-graphql-response", {
514
- requestId,
515
- ok: false,
516
- error: { message: "Invalid GraphQL query: query must be a string" },
517
- });
518
- return;
519
- }
520
- if (variables != null && (typeof variables !== "object" || Array.isArray(variables))) {
521
- this._postToIframe("bridge-graphql-response", {
522
- requestId,
523
- ok: false,
524
- error: { message: "Invalid GraphQL variables: must be a plain object" },
525
- });
526
- return;
527
- }
528
- if (this._pendingGraphQLCount >= InternalHostLwcShell.MAX_CONCURRENT_GRAPHQL) {
529
- this._postToIframe("bridge-graphql-response", {
530
- requestId,
531
- ok: false,
532
- error: { message: "Too many concurrent GraphQL requests" },
533
- });
534
- return;
535
- }
536
- this._pendingGraphQLCount++;
537
- try {
538
- const result = await executeGraphQL(query, variables);
539
- this._postToIframe("bridge-graphql-response", { requestId, ok: true, result });
540
- }
541
- catch (err) {
542
- this._postToIframe("bridge-graphql-response", {
543
- requestId,
544
- ok: false,
545
- error: { message: err?.message || "GraphQL request failed" },
546
- });
547
- }
548
- finally {
549
- this._pendingGraphQLCount--;
550
- }
551
- }
552
613
  _handleContainerClick() {
553
614
  // placeholder
554
615
  }
@@ -586,6 +647,7 @@ class InternalHostLwcShell extends HTMLElement {
586
647
  return;
587
648
  // reset tracking
588
649
  this._bridgeReady = false;
650
+ this._graphqlHandler.reset();
589
651
  this._currentState = STATES.LOADING;
590
652
  this._updateContainerState();
591
653
  // clear existing
@@ -1,4 +1,4 @@
1
- /*! @salesforce/experimental-mfe-lwc-shell v2.2.0-rc.2 (2026-03-20) */
1
+ /*! @salesforce/experimental-mfe-lwc-shell v2.2.1-rc.0 (2026-04-08) */
2
2
  var LwcShell = (function (exports, graphql) {
3
3
  'use strict';
4
4
 
@@ -29,6 +29,108 @@ var LwcShell = (function (exports, graphql) {
29
29
  const result = await graphql.unstable_graphql_imperative({ query: documentNode, variables });
30
30
  return { data: result?.data, errors: result?.errors };
31
31
  }
32
+ class GraphQLBridgeHandler {
33
+ #sendResponse;
34
+ #pendingCount = 0;
35
+ #queue = [];
36
+ #maxConcurrent;
37
+ #maxQueueSize;
38
+ #generation = 0;
39
+ constructor(sendResponse, maxConcurrent = 10, maxQueueSize = 50) {
40
+ this.#sendResponse = sendResponse;
41
+ this.#maxConcurrent = maxConcurrent;
42
+ this.#maxQueueSize = maxQueueSize;
43
+ }
44
+ static isValidRequest(data) {
45
+ const req = data;
46
+ return (typeof req?.requestId === "string" &&
47
+ typeof req?.query === "string" &&
48
+ (req.variables == null || (typeof req.variables === "object" && !Array.isArray(req.variables))));
49
+ }
50
+ rejectInvalidRequest(data) {
51
+ const req = data;
52
+ if (typeof req?.requestId !== "string") {
53
+ this.#sendResponse({
54
+ requestId: req?.requestId,
55
+ ok: false,
56
+ error: { message: "Invalid GraphQL request data" },
57
+ });
58
+ return;
59
+ }
60
+ const { requestId, query, variables } = req;
61
+ if (typeof query !== "string") {
62
+ this.#sendResponse({
63
+ requestId: requestId,
64
+ ok: false,
65
+ error: { message: "Invalid GraphQL query: query must be a string" },
66
+ });
67
+ return;
68
+ }
69
+ if (variables != null && (typeof variables !== "object" || Array.isArray(variables))) {
70
+ this.#sendResponse({
71
+ requestId: requestId,
72
+ ok: false,
73
+ error: { message: "Invalid GraphQL variables: must be a plain object" },
74
+ });
75
+ }
76
+ }
77
+ handleRequest({ requestId, query, variables }) {
78
+ if (this.#pendingCount >= this.#maxConcurrent) {
79
+ return this.#enqueueRequest(requestId, query, variables);
80
+ }
81
+ return this.#execute(requestId, query, variables);
82
+ }
83
+ reset() {
84
+ this.#generation++;
85
+ this.#queue = [];
86
+ this.#pendingCount = 0;
87
+ }
88
+ #execute = async (requestId, query, variables) => {
89
+ const gen = this.#generation;
90
+ this.#pendingCount++;
91
+ try {
92
+ const result = await executeGraphQL(query, variables);
93
+ if (gen === this.#generation) {
94
+ this.#sendResponse({ requestId, ok: true, result });
95
+ }
96
+ }
97
+ catch (err) {
98
+ if (gen === this.#generation) {
99
+ this.#sendResponse({
100
+ requestId,
101
+ ok: false,
102
+ error: { message: err?.message || "GraphQL request failed" },
103
+ });
104
+ }
105
+ }
106
+ finally {
107
+ if (gen === this.#generation) {
108
+ this.#pendingCount--;
109
+ this.#processRequestQueue();
110
+ }
111
+ }
112
+ };
113
+ #enqueueRequest = (requestId, query, variables) => {
114
+ if (this.#queue.length >= this.#maxQueueSize) {
115
+ this.#sendResponse({
116
+ requestId,
117
+ ok: false,
118
+ error: { message: "Too many queued GraphQL requests" },
119
+ });
120
+ return Promise.resolve();
121
+ }
122
+ return new Promise((resolve) => {
123
+ this.#queue.push({ requestId, query, variables, done: resolve });
124
+ });
125
+ };
126
+ #processRequestQueue = () => {
127
+ if (this.#queue.length === 0 || this.#pendingCount >= this.#maxConcurrent) {
128
+ return;
129
+ }
130
+ const next = this.#queue.shift();
131
+ this.#execute(next.requestId, next.query, next.variables).then(next.done);
132
+ };
133
+ }
32
134
 
33
135
  /**
34
136
  * InternalHostLwcShell
@@ -52,6 +154,8 @@ var LwcShell = (function (exports, graphql) {
52
154
  *
53
155
  * See the README and the `productRegistration` demo for a full recipe.
54
156
  */
157
+ const MAX_CONCURRENT_GRAPHQL_REQUESTS = 10;
158
+ const MAX_GRAPHQL_QUEUE_SIZE = 50;
55
159
  const BASE_TOKENS = ["allow-scripts", "allow-pointer-lock"];
56
160
  const OPTIONAL_TOKENS = ["allow-downloads", "allow-forms", "allow-modals"];
57
161
  const BLOCKED_TOKENS = ["allow-same-origin", "allow-top-navigation", "allow-popups"];
@@ -148,14 +252,16 @@ var LwcShell = (function (exports, graphql) {
148
252
  _title = "Embedded widget";
149
253
  _view = "compact";
150
254
  _debugEnabled = true;
151
- _pendingGraphQLCount = 0;
152
- static MAX_CONCURRENT_GRAPHQL = 10;
255
+ _graphqlHandler;
153
256
  static get observedAttributes() {
154
257
  return ["src", "srcdoc", "sandbox", "title", "view", "debug"];
155
258
  }
156
259
  constructor() {
157
260
  super();
158
261
  this._shadow = this.attachShadow({ mode: "closed" });
262
+ this._graphqlHandler = new GraphQLBridgeHandler((data) => {
263
+ this._postToIframe("bridge-graphql-response", data);
264
+ }, MAX_CONCURRENT_GRAPHQL_REQUESTS, MAX_GRAPHQL_QUEUE_SIZE);
159
265
  }
160
266
  connectedCallback() {
161
267
  this._renderInitial();
@@ -164,6 +270,7 @@ var LwcShell = (function (exports, graphql) {
164
270
  }
165
271
  disconnectedCallback() {
166
272
  window.removeEventListener("message", this._handleMessage);
273
+ this._graphqlHandler.reset();
167
274
  if (this._readinessTimeout) {
168
275
  clearTimeout(this._readinessTimeout);
169
276
  this._readinessTimeout = null;
@@ -429,7 +536,12 @@ var LwcShell = (function (exports, graphql) {
429
536
  }
430
537
  }
431
538
  else if (type === "bridge-graphql-request") {
432
- this._handleGraphQLRequest(data);
539
+ if (GraphQLBridgeHandler.isValidRequest(data)) {
540
+ this._graphqlHandler.handleRequest(data);
541
+ }
542
+ else {
543
+ this._graphqlHandler.rejectInvalidRequest(data);
544
+ }
433
545
  }
434
546
  else if (type === "bridge-ready") {
435
547
  this._handleBridgeReady();
@@ -499,57 +611,6 @@ var LwcShell = (function (exports, graphql) {
499
611
  this.dispatchEvent(new CustomEvent("widget-bridge-error", { detail: errorData }));
500
612
  this._log("bridge-error", errorData);
501
613
  }
502
- async _handleGraphQLRequest(data) {
503
- if (typeof data?.requestId !== "string") {
504
- this._log("_handleGraphQLRequest: invalid request data", data);
505
- this._postToIframe("bridge-graphql-response", {
506
- requestId: data?.requestId,
507
- ok: false,
508
- error: { message: "Invalid GraphQL request data" },
509
- });
510
- return;
511
- }
512
- const { requestId, query, variables } = data;
513
- if (typeof query !== "string") {
514
- this._postToIframe("bridge-graphql-response", {
515
- requestId,
516
- ok: false,
517
- error: { message: "Invalid GraphQL query: query must be a string" },
518
- });
519
- return;
520
- }
521
- if (variables != null && (typeof variables !== "object" || Array.isArray(variables))) {
522
- this._postToIframe("bridge-graphql-response", {
523
- requestId,
524
- ok: false,
525
- error: { message: "Invalid GraphQL variables: must be a plain object" },
526
- });
527
- return;
528
- }
529
- if (this._pendingGraphQLCount >= InternalHostLwcShell.MAX_CONCURRENT_GRAPHQL) {
530
- this._postToIframe("bridge-graphql-response", {
531
- requestId,
532
- ok: false,
533
- error: { message: "Too many concurrent GraphQL requests" },
534
- });
535
- return;
536
- }
537
- this._pendingGraphQLCount++;
538
- try {
539
- const result = await executeGraphQL(query, variables);
540
- this._postToIframe("bridge-graphql-response", { requestId, ok: true, result });
541
- }
542
- catch (err) {
543
- this._postToIframe("bridge-graphql-response", {
544
- requestId,
545
- ok: false,
546
- error: { message: err?.message || "GraphQL request failed" },
547
- });
548
- }
549
- finally {
550
- this._pendingGraphQLCount--;
551
- }
552
- }
553
614
  _handleContainerClick() {
554
615
  // placeholder
555
616
  }
@@ -587,6 +648,7 @@ var LwcShell = (function (exports, graphql) {
587
648
  return;
588
649
  // reset tracking
589
650
  this._bridgeReady = false;
651
+ this._graphqlHandler.reset();
590
652
  this._currentState = STATES.LOADING;
591
653
  this._updateContainerState();
592
654
  // clear existing
@@ -1,5 +1,5 @@
1
- /*! @salesforce/experimental-mfe-lwc-shell v2.2.0-rc.2 (2026-03-20) */
2
- var LwcShell=function(e,t){"use strict";const s=["allow-scripts","allow-pointer-lock"],i=["allow-downloads","allow-forms","allow-modals"],a=["allow-same-origin","allow-top-navigation","allow-popups"],n="state-loading",r="state-loaded";class l extends HTMLElement{_shadow;_iframe=null;_container=null;_currentState=n;_readinessTimeout=null;_isFullscreen=!1;_preFullscreenHeight="";_lastThemeData={};_lastPayloadData={};_bridgeReady=!1;_shellInstanceId=function(){return Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(36)}();_hasSentTheme=!1;_hasSentData=!1;_src=null;_srcdoc=null;_sandbox=null;_title="Embedded widget";_view="compact";_debugEnabled=!0;_pendingGraphQLCount=0;static MAX_CONCURRENT_GRAPHQL=10;static get observedAttributes(){return["src","srcdoc","sandbox","title","view","debug"]}constructor(){super(),this._shadow=this.attachShadow({mode:"closed"})}connectedCallback(){this._renderInitial(),this._setupMessageListener(),this._log("connectedCallback")}disconnectedCallback(){window.removeEventListener("message",this._handleMessage),this._readinessTimeout&&(clearTimeout(this._readinessTimeout),this._readinessTimeout=null),this._log("disconnectedCallback")}attributeChangedCallback(e,t,s){if(t!==s)switch(e){case"src":this.src=s;break;case"srcdoc":this.srcdoc=s;break;case"sandbox":this.sandbox=s;break;case"title":this.title=s;break;case"view":this.view=s;break;case"debug":this.debug=null!==s}}get src(){return this._src}set src(e){const t=e||null;this._src!==t&&(this._src=t,null!==t?this.setAttribute("src",t):this.removeAttribute("src"),this._updateIframeSrc())}get srcdoc(){return this._srcdoc}set srcdoc(e){const t=e||null;this._srcdoc!==t&&(this._srcdoc=t,null!==t?this.setAttribute("srcdoc",t):this.removeAttribute("srcdoc"),this._updateIframeSrc())}get sandbox(){return this._sandbox}set sandbox(e){const t=e||null;this._sandbox!==t&&(this._sandbox=t,null!==t?this.setAttribute("sandbox",t):this.removeAttribute("sandbox"),this._applySandbox())}get title(){return this._title}set title(e){const t=e||"Embedded widget";this._title!==t&&(this._title=t,this.setAttribute("title",t),this._updateTitle())}get view(){return this._view}set view(e){const t="full"===e?"full":"compact";this._view!==t&&(this._view=t,this.setAttribute("view",t),this._updateViewDOM())}get debug(){return this._debugEnabled}set debug(e){const t=!!e;this._debugEnabled!==t&&(this._debugEnabled=t,t?this.setAttribute("debug",""):this.removeAttribute("debug"))}updateData(e){if(!e||"object"!=typeof e)return;Object.entries(e).forEach(([e,t])=>{const s=`data-${String(e).replace(/[A-Z]/g,"-$&").toLowerCase()}`;this.setAttribute(s,String(t))});const t=this._collectDataAttributes();this._lastPayloadData=t,this._bridgeReady?(this._postToIframe("data",t),this._hasSentData=!0,this._log("send data",t)):this._log("queue data until bridge ready",t)}refreshTheme(){this._sendInitialTheme()}get _isFullView(){return"full"===this._view}get _frameClass(){return this._isFullView?"frame frameFull":"frame"}_log(...e){this._debugEnabled&&console.log("[InternalHostLwcShell]",JSON.stringify(e,null,2))}_renderInitial(){const e=this._shadow;e.innerHTML=`\n <style>\n:host {\n display: block;\n position: relative;\n height: 100%;\n overflow: auto;\n box-sizing: border-box;\n}\n\n.container {\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.frame {\n visibility: hidden;\n display: block;\n width: 100%;\n height: 100%;\n border: none;\n}\n\n.container[data-state='state-loaded'] .frame {\n visibility: visible;\n}\n\n/* Fullscreen overlay */\n.overlayBackdrop {\n position: fixed;\n inset: 0;\n width: 100vw;\n height: 100vh;\n z-index: 9998;\n background: rgba(0, 0, 0, 0.8);\n backdrop-filter: blur(4px);\n}\n\n.overlayClose {\n position: fixed;\n top: 24px;\n right: 24px;\n z-index: 9999;\n width: 32px;\n height: 32px;\n background: rgba(0, 0, 0, 0.7);\n color: #fff;\n border-radius: 50%;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: bold;\n cursor: pointer;\n}\n\n.frameFull {\n position: fixed;\n inset: 0;\n width: 90vw;\n height: 90vh !important;\n margin: 5vh 5vw;\n z-index: 10000;\n background: #fff;\n border-radius: 8px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);\n}\n</style>\n <div class="container" data-state="${this._currentState}"\n tabindex="0" role="region" aria-label="${this._title}">\n <iframe\n class="${this._frameClass}"\n title="${this._title}"\n aria-label="Interactive widget content"\n ></iframe>\n </div>\n `,this._container=e.querySelector(".container"),this._iframe=e.querySelector("iframe"),this._container.addEventListener("click",()=>this._handleContainerClick()),this._applySandbox(),this._updateIframeSrc(),this._sendInitialTheme(),this._log("renderInitial: iframe ready")}_updateContainerState(){this._container&&this._container.setAttribute("data-state",this._currentState)}_updateTitle(){this._iframe&&this._iframe.setAttribute("title",this._title),this._container&&this._container.setAttribute("aria-label",this._title),this._log("title",this._title)}_updateViewDOM(){if(this._iframe&&(this._iframe.className=this._frameClass),!this._container)return;const e=this._container.querySelector(".overlayBackdrop"),t=this._container.querySelector(".overlayClose");if(e&&e.remove(),t&&t.remove(),this._isFullView){const e=document.createElement("div");e.className="overlayBackdrop",e.setAttribute("aria-hidden","true");const t=document.createElement("button");t.className="overlayClose",t.type="button",t.setAttribute("aria-label","Close fullscreen"),t.textContent="✕",t.addEventListener("click",this._exitFullscreen),this._container.appendChild(e),this._container.appendChild(t)}}_setState(e){this._currentState=e,this._updateContainerState(),e===r&&this._sendInitialData()}_setupMessageListener(){window.addEventListener("message",this._handleMessage)}_handleMessage=e=>{const t=this._iframe?.contentWindow;if(e.source!==t)return;const s=e.data||{},{type:i,data:a,id:n}=s;if(n?n===this._shellInstanceId:"bridge-ready"===i)if(this._log("receive",i,a),"bridge-event"===i){const{eventType:e,detail:t}=a||{};if(this._log("bridge-event",e,t),"resize"===e)this._handleResize(t);else{if("widget-ready"!==e)throw new RangeError(`Invalid bridge event ${e}`);this._handleWidgetReady()}}else if("custom-event"===i){const{eventType:e,detail:t}=a||{};if(this._log("custom-event",e,t),"fullscreen-request"===e){this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0}))&&this._handleFullscreenRequest()}else"trackdirtystate"===e&&this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0,composed:!0}))}else"bridge-graphql-request"===i?this._handleGraphQLRequest(a):"bridge-ready"===i?this._handleBridgeReady():"bridge-error"===i&&this._handleBridgeError(a)};_handleResize({height:e}){const t=new CustomEvent("resize",{detail:{height:e},cancelable:!0});this.dispatchEvent(t),t.defaultPrevented||this._isFullscreen||"number"!=typeof e||!Number.isFinite(e)||(this._iframe&&(this._iframe.style.height=e+"px"),this._log("applied resize",e))}_handleWidgetReady(){this._readinessTimeout&&(clearTimeout(this._readinessTimeout),this._readinessTimeout=null),this.dispatchEvent(new CustomEvent("widget-ready",{bubbles:!0})),this._log("widget-ready")}_handleFullscreenRequest(){this._isFullscreen||this._enterFullscreen()}_enterFullscreen(){this._isFullscreen=!0,this._preFullscreenHeight=this._iframe?.style.height??"",this._view="full",this._updateViewDOM(),this._iframe&&(this._iframe.style.height="100%"),this.updateData({view:"full"}),this.dispatchEvent(new CustomEvent("fullscreen-entered",{detail:{element:this},bubbles:!0})),this._log("enter fullscreen")}_exitFullscreen=()=>{this._isFullscreen=!1,this._view="compact",this._updateViewDOM(),this._iframe&&(this._iframe.style.height=this._preFullscreenHeight),this.updateData({view:"compact"}),this.dispatchEvent(new CustomEvent("fullscreen-exited",{detail:{element:this},bubbles:!0})),this._log("exit fullscreen")};_handleBridgeReady(){this._bridgeReady=!0,this._postToIframe("shell-ready"),this._setState(r)}_handleBridgeError(e){this.dispatchEvent(new CustomEvent("widget-bridge-error",{detail:e})),this._log("bridge-error",e)}async _handleGraphQLRequest(e){if("string"!=typeof e?.requestId)return this._log("_handleGraphQLRequest: invalid request data",e),void this._postToIframe("bridge-graphql-response",{requestId:e?.requestId,ok:!1,error:{message:"Invalid GraphQL request data"}});const{requestId:s,query:i,variables:a}=e;if("string"==typeof i)if(null==a||"object"==typeof a&&!Array.isArray(a))if(this._pendingGraphQLCount>=l.MAX_CONCURRENT_GRAPHQL)this._postToIframe("bridge-graphql-response",{requestId:s,ok:!1,error:{message:"Too many concurrent GraphQL requests"}});else{this._pendingGraphQLCount++;try{const e=await async function(e,s){if("string"!=typeof e||""===e.trim())throw new Error("Invalid GraphQL query: query must be a non-empty string.");const i=t.gql`
1
+ /*! @salesforce/experimental-mfe-lwc-shell v2.2.1-rc.0 (2026-04-08) */
2
+ var LwcShell=function(e,t){"use strict";class s{#e;#t=0;#s=[];#i;#n;#a=0;constructor(e,t=10,s=50){this.#e=e,this.#i=t,this.#n=s}static isValidRequest(e){const t=e;return"string"==typeof t?.requestId&&"string"==typeof t?.query&&(null==t.variables||"object"==typeof t.variables&&!Array.isArray(t.variables))}rejectInvalidRequest(e){const t=e;if("string"!=typeof t?.requestId)return void this.#e({requestId:t?.requestId,ok:!1,error:{message:"Invalid GraphQL request data"}});const{requestId:s,query:i,variables:n}=t;"string"==typeof i?null==n||"object"==typeof n&&!Array.isArray(n)||this.#e({requestId:s,ok:!1,error:{message:"Invalid GraphQL variables: must be a plain object"}}):this.#e({requestId:s,ok:!1,error:{message:"Invalid GraphQL query: query must be a string"}})}handleRequest({requestId:e,query:t,variables:s}){return this.#t>=this.#i?this.#r(e,t,s):this.#l(e,t,s)}reset(){this.#a++,this.#s=[],this.#t=0}#l=async(e,s,i)=>{const n=this.#a;this.#t++;try{const a=await async function(e,s){if("string"!=typeof e||""===e.trim())throw new Error("Invalid GraphQL query: query must be a non-empty string.");const i=t.gql`
3
3
  ${e}
4
- `,a=await t.unstable_graphql_imperative({query:i,variables:s});return{data:a?.data,errors:a?.errors}}(i,a);this._postToIframe("bridge-graphql-response",{requestId:s,ok:!0,result:e})}catch(e){this._postToIframe("bridge-graphql-response",{requestId:s,ok:!1,error:{message:e?.message||"GraphQL request failed"}})}finally{this._pendingGraphQLCount--}}else this._postToIframe("bridge-graphql-response",{requestId:s,ok:!1,error:{message:"Invalid GraphQL variables: must be a plain object"}});else this._postToIframe("bridge-graphql-response",{requestId:s,ok:!1,error:{message:"Invalid GraphQL query: query must be a string"}})}_handleContainerClick(){}_applySandbox(){const e=this._iframe;if(!e)return;const t=this._computeSandboxTokens();e.setAttribute("sandbox",t),this._log("sandbox",t)}_computeSandboxTokens(){const e=[...s];if(this._sandbox){String(this._sandbox).split(/\s+/).filter(Boolean).forEach(t=>{i.includes(t)&&!e.includes(t)&&e.push(t),a.includes(t)&&this.dispatchEvent(new CustomEvent("security-violation",{detail:{type:"blocked-sandbox-token",token:t,element:this}}))})}return e.join(" ")}_updateIframeSrc(){const e=this._iframe;if(e){if(this._bridgeReady=!1,this._currentState=n,this._updateContainerState(),e.removeAttribute("src"),e.removeAttribute("srcdoc"),this._src)e.setAttribute("src",this._src);else if(this._srcdoc)try{e.setAttribute("srcdoc",this._srcdoc)}catch{e.setAttribute("src","about:blank")}e.onload=this._handleIframeLoad,e.onerror=this._handleIframeError,this._log("updateIframeSrc",this._src?"src":this._srcdoc?"srcdoc":"blank")}}_handleIframeLoad=()=>{this.dispatchEvent(new CustomEvent("iframe-loaded",{detail:{element:this},bubbles:!0})),this._log("iframe-loaded"),this._readinessTimeout=setTimeout(()=>{this._currentState!==r&&(this.dispatchEvent(new CustomEvent("widget-readiness-warning",{detail:{element:this,message:"Widget may not be using Bridge for readiness signaling"},bubbles:!0})),this._log("widget-readiness-warning"))},3e3)};_handleIframeError=e=>{this.dispatchEvent(new CustomEvent("widget-error",{detail:{error:e,element:this}}))};_postToIframe(e,t){const s=this._iframe?.contentWindow;if(s)try{const i=`salesforce-${e}`;s.postMessage({type:i,data:t,id:this._shellInstanceId},"*"),this._log("postMessage",i,t)}catch(e){this._log("postMessage error",e instanceof Error?e.message:String(e))}}_collectDataAttributes(){const e={};for(let t=0;t<this.attributes.length;t++){const s=this.attributes[t];if(s.name.startsWith("data-")){e[s.name.replace(/^data-/,"").replace(/-([a-z])/g,(e,t)=>t.toUpperCase())]=s.value}}return e}_sendInitialTheme(){const e=getComputedStyle(this),t={};for(let s=0;s<e.length;s++){const i=e[s];if(i.startsWith("--")){const s=e.getPropertyValue(i).trim();s&&(t[i]=s)}}this._lastThemeData=t,this._bridgeReady?(this._postToIframe("theme",t),this._hasSentTheme=!0,this._log("send theme",t)):this._log("queue theme until bridge ready",t)}_sendInitialData(){this._lastThemeData&&Object.keys(this._lastThemeData).length&&(this._postToIframe("theme",this._lastThemeData),this._hasSentTheme=!0,this._log("send theme (initial)",this._lastThemeData));const e=this._collectDataAttributes();this._lastPayloadData={...e},this._postToIframe("data",this._lastPayloadData),this._hasSentData=!0,this._log("send data (initial)",this._lastPayloadData)}}return window.customElements.get("lwc-shell")||window.customElements.define("lwc-shell",l),e.InternalHostLwcShell=l,e.default=l,Object.defineProperty(e,"__esModule",{value:!0}),e}({},"undefined"!=typeof lightningGraphql?lightningGraphql:{});
4
+ `,n=await t.unstable_graphql_imperative({query:i,variables:s});return{data:n?.data,errors:n?.errors}}(s,i);n===this.#a&&this.#e({requestId:e,ok:!0,result:a})}catch(t){n===this.#a&&this.#e({requestId:e,ok:!1,error:{message:t?.message||"GraphQL request failed"}})}finally{n===this.#a&&(this.#t--,this.#o())}};#r=(e,t,s)=>this.#s.length>=this.#n?(this.#e({requestId:e,ok:!1,error:{message:"Too many queued GraphQL requests"}}),Promise.resolve()):new Promise(i=>{this.#s.push({requestId:e,query:t,variables:s,done:i})});#o=()=>{if(0===this.#s.length||this.#t>=this.#i)return;const e=this.#s.shift();this.#l(e.requestId,e.query,e.variables).then(e.done)}}const i=["allow-scripts","allow-pointer-lock"],n=["allow-downloads","allow-forms","allow-modals"],a=["allow-same-origin","allow-top-navigation","allow-popups"],r="state-loading",l="state-loaded";class o extends HTMLElement{_shadow;_iframe=null;_container=null;_currentState=r;_readinessTimeout=null;_isFullscreen=!1;_preFullscreenHeight="";_lastThemeData={};_lastPayloadData={};_bridgeReady=!1;_shellInstanceId=function(){return Math.floor(Math.random()*Number.MAX_SAFE_INTEGER).toString(36)}();_hasSentTheme=!1;_hasSentData=!1;_src=null;_srcdoc=null;_sandbox=null;_title="Embedded widget";_view="compact";_debugEnabled=!0;_graphqlHandler;static get observedAttributes(){return["src","srcdoc","sandbox","title","view","debug"]}constructor(){super(),this._shadow=this.attachShadow({mode:"closed"}),this._graphqlHandler=new s(e=>{this._postToIframe("bridge-graphql-response",e)},10,50)}connectedCallback(){this._renderInitial(),this._setupMessageListener(),this._log("connectedCallback")}disconnectedCallback(){window.removeEventListener("message",this._handleMessage),this._graphqlHandler.reset(),this._readinessTimeout&&(clearTimeout(this._readinessTimeout),this._readinessTimeout=null),this._log("disconnectedCallback")}attributeChangedCallback(e,t,s){if(t!==s)switch(e){case"src":this.src=s;break;case"srcdoc":this.srcdoc=s;break;case"sandbox":this.sandbox=s;break;case"title":this.title=s;break;case"view":this.view=s;break;case"debug":this.debug=null!==s}}get src(){return this._src}set src(e){const t=e||null;this._src!==t&&(this._src=t,null!==t?this.setAttribute("src",t):this.removeAttribute("src"),this._updateIframeSrc())}get srcdoc(){return this._srcdoc}set srcdoc(e){const t=e||null;this._srcdoc!==t&&(this._srcdoc=t,null!==t?this.setAttribute("srcdoc",t):this.removeAttribute("srcdoc"),this._updateIframeSrc())}get sandbox(){return this._sandbox}set sandbox(e){const t=e||null;this._sandbox!==t&&(this._sandbox=t,null!==t?this.setAttribute("sandbox",t):this.removeAttribute("sandbox"),this._applySandbox())}get title(){return this._title}set title(e){const t=e||"Embedded widget";this._title!==t&&(this._title=t,this.setAttribute("title",t),this._updateTitle())}get view(){return this._view}set view(e){const t="full"===e?"full":"compact";this._view!==t&&(this._view=t,this.setAttribute("view",t),this._updateViewDOM())}get debug(){return this._debugEnabled}set debug(e){const t=!!e;this._debugEnabled!==t&&(this._debugEnabled=t,t?this.setAttribute("debug",""):this.removeAttribute("debug"))}updateData(e){if(!e||"object"!=typeof e)return;Object.entries(e).forEach(([e,t])=>{const s=`data-${String(e).replace(/[A-Z]/g,"-$&").toLowerCase()}`;this.setAttribute(s,String(t))});const t=this._collectDataAttributes();this._lastPayloadData=t,this._bridgeReady?(this._postToIframe("data",t),this._hasSentData=!0,this._log("send data",t)):this._log("queue data until bridge ready",t)}refreshTheme(){this._sendInitialTheme()}get _isFullView(){return"full"===this._view}get _frameClass(){return this._isFullView?"frame frameFull":"frame"}_log(...e){this._debugEnabled&&console.log("[InternalHostLwcShell]",JSON.stringify(e,null,2))}_renderInitial(){const e=this._shadow;e.innerHTML=`\n <style>\n:host {\n display: block;\n position: relative;\n height: 100%;\n overflow: auto;\n box-sizing: border-box;\n}\n\n.container {\n width: 100%;\n height: 100%;\n position: relative;\n}\n\n.frame {\n visibility: hidden;\n display: block;\n width: 100%;\n height: 100%;\n border: none;\n}\n\n.container[data-state='state-loaded'] .frame {\n visibility: visible;\n}\n\n/* Fullscreen overlay */\n.overlayBackdrop {\n position: fixed;\n inset: 0;\n width: 100vw;\n height: 100vh;\n z-index: 9998;\n background: rgba(0, 0, 0, 0.8);\n backdrop-filter: blur(4px);\n}\n\n.overlayClose {\n position: fixed;\n top: 24px;\n right: 24px;\n z-index: 9999;\n width: 32px;\n height: 32px;\n background: rgba(0, 0, 0, 0.7);\n color: #fff;\n border-radius: 50%;\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: bold;\n cursor: pointer;\n}\n\n.frameFull {\n position: fixed;\n inset: 0;\n width: 90vw;\n height: 90vh !important;\n margin: 5vh 5vw;\n z-index: 10000;\n background: #fff;\n border-radius: 8px;\n box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);\n}\n</style>\n <div class="container" data-state="${this._currentState}"\n tabindex="0" role="region" aria-label="${this._title}">\n <iframe\n class="${this._frameClass}"\n title="${this._title}"\n aria-label="Interactive widget content"\n ></iframe>\n </div>\n `,this._container=e.querySelector(".container"),this._iframe=e.querySelector("iframe"),this._container.addEventListener("click",()=>this._handleContainerClick()),this._applySandbox(),this._updateIframeSrc(),this._sendInitialTheme(),this._log("renderInitial: iframe ready")}_updateContainerState(){this._container&&this._container.setAttribute("data-state",this._currentState)}_updateTitle(){this._iframe&&this._iframe.setAttribute("title",this._title),this._container&&this._container.setAttribute("aria-label",this._title),this._log("title",this._title)}_updateViewDOM(){if(this._iframe&&(this._iframe.className=this._frameClass),!this._container)return;const e=this._container.querySelector(".overlayBackdrop"),t=this._container.querySelector(".overlayClose");if(e&&e.remove(),t&&t.remove(),this._isFullView){const e=document.createElement("div");e.className="overlayBackdrop",e.setAttribute("aria-hidden","true");const t=document.createElement("button");t.className="overlayClose",t.type="button",t.setAttribute("aria-label","Close fullscreen"),t.textContent="✕",t.addEventListener("click",this._exitFullscreen),this._container.appendChild(e),this._container.appendChild(t)}}_setState(e){this._currentState=e,this._updateContainerState(),e===l&&this._sendInitialData()}_setupMessageListener(){window.addEventListener("message",this._handleMessage)}_handleMessage=e=>{const t=this._iframe?.contentWindow;if(e.source!==t)return;const i=e.data||{},{type:n,data:a,id:r}=i;if(r?r===this._shellInstanceId:"bridge-ready"===n)if(this._log("receive",n,a),"bridge-event"===n){const{eventType:e,detail:t}=a||{};if(this._log("bridge-event",e,t),"resize"===e)this._handleResize(t);else{if("widget-ready"!==e)throw new RangeError(`Invalid bridge event ${e}`);this._handleWidgetReady()}}else if("custom-event"===n){const{eventType:e,detail:t}=a||{};if(this._log("custom-event",e,t),"fullscreen-request"===e){this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0}))&&this._handleFullscreenRequest()}else"trackdirtystate"===e&&this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0,composed:!0}))}else"bridge-graphql-request"===n?s.isValidRequest(a)?this._graphqlHandler.handleRequest(a):this._graphqlHandler.rejectInvalidRequest(a):"bridge-ready"===n?this._handleBridgeReady():"bridge-error"===n&&this._handleBridgeError(a)};_handleResize({height:e}){const t=new CustomEvent("resize",{detail:{height:e},cancelable:!0});this.dispatchEvent(t),t.defaultPrevented||this._isFullscreen||"number"!=typeof e||!Number.isFinite(e)||(this._iframe&&(this._iframe.style.height=e+"px"),this._log("applied resize",e))}_handleWidgetReady(){this._readinessTimeout&&(clearTimeout(this._readinessTimeout),this._readinessTimeout=null),this.dispatchEvent(new CustomEvent("widget-ready",{bubbles:!0})),this._log("widget-ready")}_handleFullscreenRequest(){this._isFullscreen||this._enterFullscreen()}_enterFullscreen(){this._isFullscreen=!0,this._preFullscreenHeight=this._iframe?.style.height??"",this._view="full",this._updateViewDOM(),this._iframe&&(this._iframe.style.height="100%"),this.updateData({view:"full"}),this.dispatchEvent(new CustomEvent("fullscreen-entered",{detail:{element:this},bubbles:!0})),this._log("enter fullscreen")}_exitFullscreen=()=>{this._isFullscreen=!1,this._view="compact",this._updateViewDOM(),this._iframe&&(this._iframe.style.height=this._preFullscreenHeight),this.updateData({view:"compact"}),this.dispatchEvent(new CustomEvent("fullscreen-exited",{detail:{element:this},bubbles:!0})),this._log("exit fullscreen")};_handleBridgeReady(){this._bridgeReady=!0,this._postToIframe("shell-ready"),this._setState(l)}_handleBridgeError(e){this.dispatchEvent(new CustomEvent("widget-bridge-error",{detail:e})),this._log("bridge-error",e)}_handleContainerClick(){}_applySandbox(){const e=this._iframe;if(!e)return;const t=this._computeSandboxTokens();e.setAttribute("sandbox",t),this._log("sandbox",t)}_computeSandboxTokens(){const e=[...i];if(this._sandbox){String(this._sandbox).split(/\s+/).filter(Boolean).forEach(t=>{n.includes(t)&&!e.includes(t)&&e.push(t),a.includes(t)&&this.dispatchEvent(new CustomEvent("security-violation",{detail:{type:"blocked-sandbox-token",token:t,element:this}}))})}return e.join(" ")}_updateIframeSrc(){const e=this._iframe;if(e){if(this._bridgeReady=!1,this._graphqlHandler.reset(),this._currentState=r,this._updateContainerState(),e.removeAttribute("src"),e.removeAttribute("srcdoc"),this._src)e.setAttribute("src",this._src);else if(this._srcdoc)try{e.setAttribute("srcdoc",this._srcdoc)}catch{e.setAttribute("src","about:blank")}e.onload=this._handleIframeLoad,e.onerror=this._handleIframeError,this._log("updateIframeSrc",this._src?"src":this._srcdoc?"srcdoc":"blank")}}_handleIframeLoad=()=>{this.dispatchEvent(new CustomEvent("iframe-loaded",{detail:{element:this},bubbles:!0})),this._log("iframe-loaded"),this._readinessTimeout=setTimeout(()=>{this._currentState!==l&&(this.dispatchEvent(new CustomEvent("widget-readiness-warning",{detail:{element:this,message:"Widget may not be using Bridge for readiness signaling"},bubbles:!0})),this._log("widget-readiness-warning"))},3e3)};_handleIframeError=e=>{this.dispatchEvent(new CustomEvent("widget-error",{detail:{error:e,element:this}}))};_postToIframe(e,t){const s=this._iframe?.contentWindow;if(s)try{const i=`salesforce-${e}`;s.postMessage({type:i,data:t,id:this._shellInstanceId},"*"),this._log("postMessage",i,t)}catch(e){this._log("postMessage error",e instanceof Error?e.message:String(e))}}_collectDataAttributes(){const e={};for(let t=0;t<this.attributes.length;t++){const s=this.attributes[t];if(s.name.startsWith("data-")){e[s.name.replace(/^data-/,"").replace(/-([a-z])/g,(e,t)=>t.toUpperCase())]=s.value}}return e}_sendInitialTheme(){const e=getComputedStyle(this),t={};for(let s=0;s<e.length;s++){const i=e[s];if(i.startsWith("--")){const s=e.getPropertyValue(i).trim();s&&(t[i]=s)}}this._lastThemeData=t,this._bridgeReady?(this._postToIframe("theme",t),this._hasSentTheme=!0,this._log("send theme",t)):this._log("queue theme until bridge ready",t)}_sendInitialData(){this._lastThemeData&&Object.keys(this._lastThemeData).length&&(this._postToIframe("theme",this._lastThemeData),this._hasSentTheme=!0,this._log("send theme (initial)",this._lastThemeData));const e=this._collectDataAttributes();this._lastPayloadData={...e},this._postToIframe("data",this._lastPayloadData),this._hasSentData=!0,this._log("send data (initial)",this._lastPayloadData)}}return window.customElements.get("lwc-shell")||window.customElements.define("lwc-shell",o),e.InternalHostLwcShell=o,e.default=o,Object.defineProperty(e,"__esModule",{value:!0}),e}({},"undefined"!=typeof lightningGraphql?lightningGraphql:{});
5
5
  //# sourceMappingURL=index.iife.prod.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforce/experimental-mfe-lwc-shell",
3
- "version": "2.2.0",
3
+ "version": "2.2.1-rc.0",
4
4
  "private": false,
5
5
  "description": "A standard Web Component shell for UI Embedding",
6
6
  "license": "SEE LICENSE IN LICENSE.txt",
@@ -1,5 +0,0 @@
1
- export declare function executeGraphQL(query: string, variables?: Record<string, any>): Promise<{
2
- data: unknown;
3
- errors?: unknown[];
4
- }>;
5
- //# sourceMappingURL=graphqlHandler.d.ts.map
@@ -1,33 +0,0 @@
1
- <!--
2
- dirtyStateModal template — shipped with @lightning-out/lwc-shell.
3
-
4
- This template is entirely generic / config-driven:
5
- - Header label, body description, and footer buttons are all bound to
6
- the `modalFields` @api property — nothing is hard-coded here.
7
- - The concrete values (e.g. "Unsaved Changes", "Discard Changes" button)
8
- are defined in InternalHostLwcShell.ts inside the
9
- `[DoCloseConfirmation]()` method and passed at open-time.
10
- - To change what the modal displays, update the config object in
11
- InternalHostLwcShell.ts, NOT this template.
12
-
13
- Customers: copy this file (along with .js and .js-meta.xml) into your
14
- SFDX project's lwc/dirtyStateModal/ folder and deploy to your org.
15
- -->
16
- <template>
17
- <lightning-modal-header label={modalFields.label}></lightning-modal-header>
18
- <lightning-modal-body>
19
- <p>{modalFields.description}</p>
20
- </lightning-modal-body>
21
- <lightning-modal-footer>
22
- <template for:each={modalFields.buttons} for:item="button">
23
- <lightning-button
24
- key={button.buttonKey}
25
- label={button.buttonLabel}
26
- variant={button.buttonVariant}
27
- data-key={button.buttonKey}
28
- onclick={handleButtonClick}
29
- class="slds-m-right_x-small"
30
- ></lightning-button>
31
- </template>
32
- </lightning-modal-footer>
33
- </template>
@@ -1,82 +0,0 @@
1
- /**
2
- * dirtyStateModal — Generic, config-driven LWC modal shipped with
3
- * @lightning-out/lwc-shell.
4
- *
5
- * IMPORTANT: This modal is intentionally **generic**. It does NOT hard-code
6
- * any specific labels, descriptions, or button definitions. Instead, it
7
- * receives all of its display configuration through the `modalFields` @api
8
- * property at open-time. This makes it reusable for any confirmation
9
- * scenario — the caller decides what the modal says and which buttons it
10
- * shows.
11
- *
12
- * The **concrete configuration** for the current lwc-shell dirty-state
13
- * flow lives in `InternalHostLwcShell.ts` inside the
14
- * `[DoCloseConfirmation]()` method, where the `dirtStateModalConfig` object
15
- * is built and passed to `DirtyStateModal.open(dirtStateModalConfig)`.
16
- * That config currently specifies:
17
- * - label: "Unsaved Changes"
18
- * - description: "You have unsaved changes. If you leave, your changes
19
- * will be lost."
20
- * - buttons: "Cancel" and "Discard Changes" (brand variant)
21
- * - size: "small"
22
- *
23
- * If you need to change the wording, add/remove buttons, or adjust the
24
- * modal size, update the config object in `InternalHostLwcShell.ts` —
25
- * **not** in this component.
26
- *
27
- * ---
28
- * Deployment: customers must copy this component from the lwc-shell
29
- * package's `dist/lwc/dirtyStateModal/` folder into their own SFDX
30
- * project and deploy it to their Salesforce org.
31
- *
32
- * Usage in wrapper LWC:
33
- * import DirtyStateModal from 'c/dirtyStateModal';
34
- * shell.dirtyStateModal = DirtyStateModal;
35
- */
36
- import LightningModal from "lightning/modal";
37
- import { api } from "lwc";
38
-
39
- export default class DirtyStateModal extends LightningModal {
40
- /**
41
- * Generic configuration object — NOT owned by this component.
42
- *
43
- * The actual values are supplied by the caller (InternalHostLwcShell)
44
- * at open-time via `DirtyStateModal.open({ modalFields: { ... } })`.
45
- * The defaults below are minimal fallbacks; the real config (label,
46
- * description, full button set) is defined in InternalHostLwcShell's
47
- * `[DoCloseConfirmation]()` method.
48
- *
49
- * Shape:
50
- * {
51
- * label: string, // Modal header text
52
- * description: string, // Modal body text
53
- * buttons: [ // Footer buttons (rendered dynamically)
54
- * {
55
- * buttonKey: string, // Unique key returned on click
56
- * buttonLabel: string, // Visible label
57
- * buttonVariant: string // Optional SLDS variant (e.g. 'brand')
58
- * }
59
- * ]
60
- * }
61
- */
62
- @api modalFields = {
63
- label: "Unsaved Changes",
64
- description: "You have unsaved changes.",
65
- buttons: [
66
- {
67
- buttonKey: "cancel",
68
- buttonLabel: "Cancel",
69
- },
70
- ],
71
- };
72
-
73
- /**
74
- * Generic button handler — closes the modal and returns the clicked
75
- * button's `buttonKey` to the caller's `.open()` promise so the caller
76
- * (InternalHostLwcShell) can decide what action to take.
77
- */
78
- handleButtonClick(event) {
79
- const key = event.target.dataset.key;
80
- this.close(key);
81
- }
82
- }
@@ -1,5 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
3
- <apiVersion>64.0</apiVersion>
4
- <isExposed>false</isExposed>
5
- </LightningComponentBundle>
@@ -1,23 +0,0 @@
1
- import { DoCloseConfirmation, Guid } from "./symbols";
2
- /**
3
- * Symbol-keyed contract for components that self-manage their dirty state.
4
- *
5
- * - `DoCloseConfirmation` — The component **must** define this as a function
6
- * that returns a `Promise` resolving to one of:
7
- * - `'SUCCESS'` – dirty state resolved, tab closure should continue.
8
- * - `'CANCEL'` – the user cancelled the operation.
9
- * - `'ERROR'` – a problem occurred resolving the dirty state.
10
- *
11
- * If the promise resolves to `'SUCCESS'`, the component **must** have
12
- * already dispatched a `'privatelightningselfmanageddirtystatechanged'`
13
- * event with `isUnsaved: false` to clear its dirty state.
14
- *
15
- * - `Guid` — Optionally, the component can define this as a property
16
- * containing a globally unique string. If undefined, a GUID will be
17
- * generated automatically.
18
- */
19
- export declare const SelfManagedDirtyComponent: Readonly<{
20
- DoCloseConfirmation: typeof DoCloseConfirmation;
21
- Guid: typeof Guid;
22
- }>;
23
- //# sourceMappingURL=dirtyStateModal.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dirtyStateModal.d.ts","sourceRoot":"","sources":["../../src/utils/dirtyStateModal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtD;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,yBAAyB,EAAE,QAAQ,CAAC;IAC7C,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,IAAI,EAAE,OAAO,IAAI,CAAC;CACrB,CAGS,CAAC"}
@@ -1,13 +0,0 @@
1
- /**
2
- * Utils barrel — re-exports all utility modules used by lwc-shell.
3
- *
4
- * This folder is designed to grow as new features are added (e.g. additional
5
- * state managers, analytics hooks). Each feature should get its own module
6
- * and be re-exported from this index.
7
- *
8
- * Currently provides:
9
- * - Dirty-state management symbols and helpers (`dirtyStateModal`, `symbols`).
10
- */
11
- export { SelfManagedDirtyComponent } from "./dirtyStateModal";
12
- export { DoCloseConfirmation, Guid } from "./symbols";
13
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,yBAAyB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC"}
@@ -1,18 +0,0 @@
1
- /**
2
- * Symbols used as property / method keys for the dirty-state contract.
3
- *
4
- * These symbols are attached to the host LWC component by `<lwc-shell>`
5
- * (via the `hostComponent` setter) so that Salesforce's tab-close flow can
6
- * invoke `DoCloseConfirmation` and identify the component by `Guid`.
7
- *
8
- * See `InternalHostLwcShell.hostComponent` setter for wiring details,
9
- * and the `SelfManagedDirtyComponent` object in `dirtyStateModal.ts` for
10
- * the full contract description.
11
- */
12
- export declare const Guid: unique symbol;
13
- export declare const DoCloseConfirmation: unique symbol;
14
- /**
15
- * Generic constructor type used by the mixin.
16
- */
17
- export type Constructor<T = HTMLElement> = new (...args: any[]) => T;
18
- //# sourceMappingURL=symbols.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"symbols.d.ts","sourceRoot":"","sources":["../../src/utils/symbols.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,IAAI,EAAE,OAAO,MAAuB,CAAC;AAClD,eAAO,MAAM,mBAAmB,EAAE,OAAO,MAAsC,CAAC;AAEhF;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,WAAW,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC"}