@lightning-out/containers 2.2.0-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.
- package/dist/modules/force/lightningOutBaseContainer/lightningOutBaseContainer.html +7 -0
- package/dist/modules/force/lightningOutBaseContainer/lightningOutBaseContainer.js +226 -0
- package/dist/modules/force/lightningOutBaseContainer/lightningOutBaseContainer.js-meta.xml +4 -0
- package/dist/modules/force/lightningOutBaseContainer/utils/contants.js +17 -0
- package/dist/modules/force/lightningOutBaseContainer/utils/env.js +56 -0
- package/dist/modules/force/lightningOutBaseContainer/utils/errorHandling.js +16 -0
- package/dist/modules/force/lightningOutBaseContainer/utils/instrumentation.js +48 -0
- package/dist/modules/force/lightningOutBaseContainer/utils/style.js +21 -0
- package/dist/modules/force/lightningOutLWRAuraContainer/lightningOutLWRAuraContainer.html +17 -0
- package/dist/modules/force/lightningOutLWRAuraContainer/lightningOutLWRAuraContainer.js +107 -0
- package/dist/modules/force/lightningOutLWRAuraContainer/lightningOutLWRAuraContainer.js-meta.xml +4 -0
- package/dist/modules/force/lightningOutLWRAuraContainer/utils/errorHandling.js +55 -0
- package/dist/modules/force/lightningOutLWRAuraContainer/utils/gater.js +14 -0
- package/dist/modules/force/lightningOutLWRContainer/lightningOutLWRContainer.html +7 -0
- package/dist/modules/force/lightningOutLWRContainer/lightningOutLWRContainer.js +7 -0
- package/dist/modules/force/lightningOutLWRContainer/lightningOutLWRContainer.js-meta.xml +8 -0
- package/dist/modules/force/lightningOutOneRuntimeContainer/lightningOutOneRuntimeContainer.html +14 -0
- package/dist/modules/force/lightningOutOneRuntimeContainer/lightningOutOneRuntimeContainer.js +38 -0
- package/dist/modules/force/lightningOutOneRuntimeContainer/lightningOutOneRuntimeContainer.js-meta.xml +4 -0
- package/dist/modules/force/lightningOutOneRuntimeContainer/utils/errorHandling.js +49 -0
- package/dist/modules/force/lightningOutOneRuntimeContainer/utils/gater.js +14 -0
- package/package.json +18 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { api, LightningElement, track } from "lwc";
|
|
8
|
+
|
|
9
|
+
import { MSG } from "./utils/contants";
|
|
10
|
+
|
|
11
|
+
import { createEnvContext } from "./utils/env";
|
|
12
|
+
import { createGlobalError } from "./utils/errorHandling";
|
|
13
|
+
|
|
14
|
+
import { createInstrumentation } from "./utils/instrumentation";
|
|
15
|
+
import { applyCustomStyleProperties } from "./utils/style";
|
|
16
|
+
|
|
17
|
+
// These settings are important for layout and sizing.
|
|
18
|
+
document.documentElement.style.height = "100%";
|
|
19
|
+
document.documentElement.style.display = "block";
|
|
20
|
+
document.body.style.margin = "0px";
|
|
21
|
+
document.body.style.height = "100%";
|
|
22
|
+
document.body.style.display = "block";
|
|
23
|
+
|
|
24
|
+
export default class LightningOutBaseContainer extends LightningElement {
|
|
25
|
+
static renderMode = "light";
|
|
26
|
+
|
|
27
|
+
#embeddedCmp;
|
|
28
|
+
embeddedCmpCtor;
|
|
29
|
+
embeddedCmpName;
|
|
30
|
+
@track embeddedCmpProps;
|
|
31
|
+
embeddedCmpType = "lwc";
|
|
32
|
+
|
|
33
|
+
#env;
|
|
34
|
+
#eventListeners = new Map();
|
|
35
|
+
#renderActivity;
|
|
36
|
+
#renderActivityStopped = false;
|
|
37
|
+
|
|
38
|
+
#globalError;
|
|
39
|
+
isError = false;
|
|
40
|
+
#instrumentation;
|
|
41
|
+
|
|
42
|
+
constructor() {
|
|
43
|
+
super();
|
|
44
|
+
this.#env = createEnvContext();
|
|
45
|
+
this.#instrumentation = createInstrumentation(
|
|
46
|
+
"LightningOutLWRApp",
|
|
47
|
+
this.#env.componentNameParam,
|
|
48
|
+
this.#env.loAppOrigin,
|
|
49
|
+
);
|
|
50
|
+
this.#globalError = createGlobalError(this.#env.parentPostMessage, this.#instrumentation.logError);
|
|
51
|
+
window.addEventListener("message", this.#messageListener);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@api
|
|
55
|
+
get embeddedCmp() {
|
|
56
|
+
return this.refs?.embeddedCmp;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
getEnv() {
|
|
60
|
+
return this.#env;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
getInstrumentation() {
|
|
64
|
+
return this.#instrumentation;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
#messageListener = (event) => {
|
|
68
|
+
// Page must be in an <iframe> unless testMode
|
|
69
|
+
if (!this.#env.testMode && window.top === window.self) {
|
|
70
|
+
window.console.trace("Lightning Out: This page is not in an <iframe>");
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
if (event.origin !== this.#env.loAppOrigin) {
|
|
74
|
+
window.console.log(
|
|
75
|
+
`Lightning Out: Message ignored due to different origin: ${event.origin} vs ${this.#env.loAppOrigin}`,
|
|
76
|
+
);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
switch (event.data.type) {
|
|
80
|
+
case MSG.ADD_EVENT_LISTENER: {
|
|
81
|
+
const eventName = event.data.name;
|
|
82
|
+
const eventOptions = event.data.options;
|
|
83
|
+
const listenerKey = event.data.listenerKey;
|
|
84
|
+
const listener = (evt) => {
|
|
85
|
+
this.#env.parentPostMessage({
|
|
86
|
+
name: eventName,
|
|
87
|
+
detail: structuredClone(evt.detail),
|
|
88
|
+
type: MSG.DISPATCH_EVENT,
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
this.#embeddedCmp.addEventListener(eventName, listener, eventOptions);
|
|
92
|
+
this.#eventListeners.set(listenerKey, listener);
|
|
93
|
+
break;
|
|
94
|
+
}
|
|
95
|
+
case MSG.DISPATCH_EVENT: {
|
|
96
|
+
const customEvent = new CustomEvent(event.data.name, {
|
|
97
|
+
detail: event.data.detail,
|
|
98
|
+
});
|
|
99
|
+
this.#embeddedCmp.dispatchEvent(customEvent);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
case MSG.REMOVE_EVENT_LISTENER: {
|
|
103
|
+
const eventName = event.data.name;
|
|
104
|
+
const eventOptions = event.data.options;
|
|
105
|
+
const listenerKey = event.data.listenerKey;
|
|
106
|
+
const listener = this.#eventListeners.get(listenerKey);
|
|
107
|
+
if (listener) {
|
|
108
|
+
this.#embeddedCmp.removeEventListener(eventName, listener, eventOptions);
|
|
109
|
+
this.#eventListeners.delete(listenerKey);
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
case MSG.SET_COMPONENT_DATA: {
|
|
114
|
+
this.renderComponent(event.data.componentData);
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
case MSG.SET_COMPONENT_PROPS: {
|
|
118
|
+
this.setComponentProps(event.data.componentProps);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
case MSG.RELOAD: {
|
|
122
|
+
window.location.reload();
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
default: {
|
|
126
|
+
// noop
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
async renderComponent(componentData) {
|
|
132
|
+
this.embeddedCmpId = componentData.id;
|
|
133
|
+
this.embeddedCmpName = componentData.name;
|
|
134
|
+
this.embeddedCmpProps = componentData.props;
|
|
135
|
+
if (!this.embeddedCmpName || !this.embeddedCmpProps) {
|
|
136
|
+
this.#globalError(`Missing 'componentName' or 'componentProps,' both must be specified.`);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const { specifier, type } = this.resolveEmbeddedCmpSpecifier(this.embeddedCmpName);
|
|
140
|
+
this.embeddedCmpType = type;
|
|
141
|
+
|
|
142
|
+
this.#renderActivity = this.#instrumentation.startRenderActivity({
|
|
143
|
+
componentName: specifier,
|
|
144
|
+
componentType: type,
|
|
145
|
+
loAppOrigin: this.#env.loAppOrigin,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const { default: ctor } = await import(specifier);
|
|
150
|
+
this.embeddedCmpCtor = ctor;
|
|
151
|
+
} catch (err) {
|
|
152
|
+
this.isError = true;
|
|
153
|
+
this.#instrumentation.errorRenderActivity(this.#renderActivity, err, {
|
|
154
|
+
componentName: specifier,
|
|
155
|
+
componentType: type,
|
|
156
|
+
componentProps: JSON.stringify(this.embeddedCmpProps || {}),
|
|
157
|
+
message: err?.message,
|
|
158
|
+
hasError: this.isError,
|
|
159
|
+
loAppOrigin: this.#env.loAppOrigin,
|
|
160
|
+
});
|
|
161
|
+
this.#globalError(err);
|
|
162
|
+
} finally {
|
|
163
|
+
if (this.isError && this.#renderActivity && !this.#renderActivityStopped) {
|
|
164
|
+
this.#instrumentation.stopRenderActivity(this.#renderActivity, {
|
|
165
|
+
componentName: specifier,
|
|
166
|
+
componentType: type,
|
|
167
|
+
hasError: this.isError,
|
|
168
|
+
loAppOrigin: this.#env.loAppOrigin,
|
|
169
|
+
});
|
|
170
|
+
this.#renderActivityStopped = true;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
setComponentProps(componentProps) {
|
|
176
|
+
if (componentProps.style && this.embeddedCmp) {
|
|
177
|
+
applyCustomStyleProperties(componentProps.style, this.embeddedCmp.style);
|
|
178
|
+
delete componentProps.style;
|
|
179
|
+
}
|
|
180
|
+
if (Object.keys(componentProps).length) {
|
|
181
|
+
this.embeddedCmpProps = componentProps;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
resolveEmbeddedCmpSpecifier(embeddedCmpName) {
|
|
186
|
+
const [name] = embeddedCmpName.split("/v/");
|
|
187
|
+
const type = name.includes(":") ? "aura" : "lwc";
|
|
188
|
+
if (type === "aura") {
|
|
189
|
+
this.#globalError("Aura components require using 'lightningOutOneRuntimeContainer' instead.");
|
|
190
|
+
}
|
|
191
|
+
return { specifier: name, type };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
connectedCallback() {
|
|
195
|
+
this.#env.parentPostMessage({ type: MSG.LOADED });
|
|
196
|
+
const componentData = this.#env.testMode ? this.#env.getComponentData() : null;
|
|
197
|
+
if (componentData) {
|
|
198
|
+
this.renderComponent(componentData);
|
|
199
|
+
} else {
|
|
200
|
+
this.#env.parentPostMessage({ type: MSG.GET_COMPONENT_DATA });
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
renderedCallback() {
|
|
205
|
+
if (!this.#embeddedCmp && this.refs?.embeddedCmp) {
|
|
206
|
+
this.#embeddedCmp = this.refs.embeddedCmp;
|
|
207
|
+
this.#embeddedCmp.addEventListener("message", (evt) => {
|
|
208
|
+
this.#env.parentPostMessage({
|
|
209
|
+
name: evt.type,
|
|
210
|
+
detail: structuredClone(evt.detail),
|
|
211
|
+
type: MSG.DISPATCH_EVENT,
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
this.#env.parentPostMessage({ type: MSG.READY });
|
|
215
|
+
if (this.#renderActivity && !this.#renderActivityStopped) {
|
|
216
|
+
this.#instrumentation.stopRenderActivity(this.#renderActivity, {
|
|
217
|
+
componentName: this.embeddedCmpName,
|
|
218
|
+
componentType: this.embeddedCmpType,
|
|
219
|
+
hasError: this.isError,
|
|
220
|
+
loAppOrigin: this.#env.loAppOrigin,
|
|
221
|
+
});
|
|
222
|
+
this.#renderActivityStopped = true;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export const MSG = {
|
|
8
|
+
LOADED: "lo.loaded",
|
|
9
|
+
READY: "lo.ready",
|
|
10
|
+
ADD_EVENT_LISTENER: "lo.addEventListener",
|
|
11
|
+
REMOVE_EVENT_LISTENER: "lo.removeEventListener",
|
|
12
|
+
DISPATCH_EVENT: "lo.dispatchEvent",
|
|
13
|
+
SET_COMPONENT_DATA: "lo.setComponentData",
|
|
14
|
+
SET_COMPONENT_PROPS: "lo.setComponentProps",
|
|
15
|
+
RELOAD: "lo.reload",
|
|
16
|
+
GET_COMPONENT_DATA: "lo.getComponentData",
|
|
17
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const urlSearchParams = new URLSearchParams(window.location.search);
|
|
8
|
+
|
|
9
|
+
export function createEnvContext() {
|
|
10
|
+
const loAppOrigin = urlSearchParams.get("loAppOrigin");
|
|
11
|
+
const parentElementId = urlSearchParams.get("parentElementId");
|
|
12
|
+
const componentNameParam = urlSearchParams.get("componentName");
|
|
13
|
+
const testMode = urlSearchParams.get("testMode") === "true";
|
|
14
|
+
|
|
15
|
+
try {
|
|
16
|
+
const isInBuilder = window.self !== window.top && window.name === "sitePreviewFrame";
|
|
17
|
+
const isInBuilderContext =
|
|
18
|
+
urlSearchParams.get("app") === "commeditor" && urlSearchParams.get("view") === "editor";
|
|
19
|
+
if (!isInBuilder && !isInBuilderContext) {
|
|
20
|
+
(() => new URL(loAppOrigin))();
|
|
21
|
+
}
|
|
22
|
+
} catch (err) {
|
|
23
|
+
throw new Error(`${err.message} (loAppOrigin: ${loAppOrigin})`);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function parentPostMessage(message) {
|
|
27
|
+
if (typeof message !== "string") {
|
|
28
|
+
message.id = parentElementId;
|
|
29
|
+
}
|
|
30
|
+
window.parent.postMessage(message, loAppOrigin);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function getComponentData() {
|
|
34
|
+
const componentProps = urlSearchParams.get("componentProps");
|
|
35
|
+
if (!componentProps) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
return {
|
|
40
|
+
name: componentNameParam,
|
|
41
|
+
props: JSON.parse(componentProps),
|
|
42
|
+
};
|
|
43
|
+
} catch {
|
|
44
|
+
throw new Error(`Invalid component properties: ${componentProps}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
loAppOrigin,
|
|
50
|
+
parentElementId,
|
|
51
|
+
componentNameParam,
|
|
52
|
+
testMode,
|
|
53
|
+
parentPostMessage,
|
|
54
|
+
getComponentData,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export function createGlobalError(parentPostMessage, logError) {
|
|
8
|
+
return function globalError(err) {
|
|
9
|
+
const msg = err?.message || `${err}`;
|
|
10
|
+
const fullMsg = `Lightning-Out Container Error: ${msg}`;
|
|
11
|
+
logError(fullMsg);
|
|
12
|
+
window.console.error(fullMsg);
|
|
13
|
+
parentPostMessage(fullMsg);
|
|
14
|
+
throw new Error(fullMsg);
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { getInstrumentation } from "o11y/client";
|
|
8
|
+
import { lightningOutComponentRenderSchema } from "o11y_schema/sf_lightningOut";
|
|
9
|
+
|
|
10
|
+
export function createInstrumentation(channelName, componentName, loAppOrigin) {
|
|
11
|
+
const instrumentation = getInstrumentation(channelName);
|
|
12
|
+
|
|
13
|
+
function logError(error) {
|
|
14
|
+
if (instrumentation) {
|
|
15
|
+
instrumentation.error(error, lightningOutComponentRenderSchema, {
|
|
16
|
+
componentName,
|
|
17
|
+
message: error.message || String(error),
|
|
18
|
+
hasError: true,
|
|
19
|
+
loAppOrigin,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function startRenderActivity(instrumentationContext) {
|
|
25
|
+
return instrumentation.startActivity("component-render", {
|
|
26
|
+
instrumentationContext,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function errorRenderActivity(activity, err, details) {
|
|
31
|
+
if (activity) {
|
|
32
|
+
activity.error(err, lightningOutComponentRenderSchema, details);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function stopRenderActivity(activity, details) {
|
|
37
|
+
if (activity) {
|
|
38
|
+
activity.stop(lightningOutComponentRenderSchema, details);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return {
|
|
43
|
+
logError,
|
|
44
|
+
startRenderActivity,
|
|
45
|
+
errorRenderActivity,
|
|
46
|
+
stopRenderActivity,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export function applyCustomStyleProperties(componentPropsStyle, embeddedCmpStyle) {
|
|
8
|
+
for (let i = 0, len = embeddedCmpStyle.length; i < len; i++) {
|
|
9
|
+
const prop = embeddedCmpStyle.item(i);
|
|
10
|
+
if (prop && prop.startsWith("--")) {
|
|
11
|
+
embeddedCmpStyle.removeProperty(prop);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
const allStyles = componentPropsStyle.split(";");
|
|
15
|
+
allStyles.forEach((style) => {
|
|
16
|
+
const [prop, val] = style.split(":");
|
|
17
|
+
if (prop && prop.trim().startsWith("--")) {
|
|
18
|
+
embeddedCmpStyle.setProperty(prop.trim(), val ?? "");
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<template lwc:render-mode="light">
|
|
2
|
+
<div lwc:if={includeBeacon}>
|
|
3
|
+
<aura-interop
|
|
4
|
+
descriptor="instrumentation:beacon"
|
|
5
|
+
config={config}
|
|
6
|
+
></aura-interop>
|
|
7
|
+
</div>
|
|
8
|
+
<lwrlex-instrumentation></lwrlex-instrumentation>
|
|
9
|
+
|
|
10
|
+
<div lwc:if={componentName}>
|
|
11
|
+
<aura-interop
|
|
12
|
+
descriptor={componentName}
|
|
13
|
+
lwc:ref="embeddedCmp"
|
|
14
|
+
lwc:spread={embeddedCmpProps}>
|
|
15
|
+
</aura-interop>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import LightningOutBaseContainer from "force/lightningOutBaseContainer";
|
|
8
|
+
|
|
9
|
+
import { createErrorHooks } from "./utils/errorHandling";
|
|
10
|
+
import { isBeaconEnabled } from "./utils/gater";
|
|
11
|
+
|
|
12
|
+
export default class LightningOutLWRAuraContainer extends LightningOutBaseContainer {
|
|
13
|
+
#includeBeacon = false;
|
|
14
|
+
componentName = null;
|
|
15
|
+
config = {
|
|
16
|
+
usePageTransactions: false,
|
|
17
|
+
disableAvroValidation: false,
|
|
18
|
+
};
|
|
19
|
+
#renderActivity;
|
|
20
|
+
#renderActivityStopped = false;
|
|
21
|
+
constructor() {
|
|
22
|
+
super();
|
|
23
|
+
this.#includeBeacon = isBeaconEnabled();
|
|
24
|
+
createErrorHooks(this.getEnv().parentPostMessage, this.getInstrumentation().logError);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get includeBeacon() {
|
|
28
|
+
return this.#includeBeacon;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
async renderComponent(componentData) {
|
|
32
|
+
if (!componentData.name) {
|
|
33
|
+
const error = new Error("LightningOutLWRAuraContainer requires 'componentName'.");
|
|
34
|
+
this.getInstrumentation().logError(error);
|
|
35
|
+
throw error;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const isAura = componentData.name.includes(":");
|
|
39
|
+
this.embeddedCmpType = isAura ? "aura" : "lwc";
|
|
40
|
+
this.embeddedCmpId = componentData.id || "componentId";
|
|
41
|
+
this.embeddedCmpName = componentData.name;
|
|
42
|
+
this.embeddedCmpProps = componentData.props || {};
|
|
43
|
+
this.componentName = componentData.name;
|
|
44
|
+
this.isError = false;
|
|
45
|
+
|
|
46
|
+
this.#renderActivityStopped = false;
|
|
47
|
+
this.#renderActivity = this.getInstrumentation().startRenderActivity(this._getInstrumentationContext());
|
|
48
|
+
|
|
49
|
+
try {
|
|
50
|
+
this.getEnv().parentPostMessage({ type: "lo.ready" });
|
|
51
|
+
} catch (err) {
|
|
52
|
+
this.isError = true;
|
|
53
|
+
this._handleRenderError(err);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
setComponentProps(componentProps) {
|
|
58
|
+
if (!componentProps) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
this.embeddedCmpProps = componentProps;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
resolveEmbeddedCmpSpecifier(embeddedCmpName) {
|
|
65
|
+
const [, version] = embeddedCmpName.split("/v/");
|
|
66
|
+
const calculatedVersion = version || "0_0_1";
|
|
67
|
+
|
|
68
|
+
return { specifier: `aura/interop/v/${calculatedVersion}`, type: "aura" };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
renderedCallback() {
|
|
72
|
+
super.renderedCallback();
|
|
73
|
+
if (this.refs?.embeddedCmp) {
|
|
74
|
+
this._stopRenderActivity();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
_handleRenderError(err) {
|
|
79
|
+
this.getInstrumentation().errorRenderActivity(this.#renderActivity, err, {
|
|
80
|
+
...this._getInstrumentationContext(),
|
|
81
|
+
componentProps: JSON.stringify(this.embeddedCmpProps || {}),
|
|
82
|
+
message: err?.message,
|
|
83
|
+
hasError: true,
|
|
84
|
+
});
|
|
85
|
+
this._stopRenderActivity({ hasError: true });
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
_stopRenderActivity(details = {}) {
|
|
89
|
+
if (!this.#renderActivity || this.#renderActivityStopped) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
this.getInstrumentation().stopRenderActivity(this.#renderActivity, {
|
|
93
|
+
...this._getInstrumentationContext(),
|
|
94
|
+
hasError: this.isError,
|
|
95
|
+
...details,
|
|
96
|
+
});
|
|
97
|
+
this.#renderActivityStopped = true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
_getInstrumentationContext() {
|
|
101
|
+
return {
|
|
102
|
+
componentName: this.embeddedCmpName,
|
|
103
|
+
componentType: this.embeddedCmpType,
|
|
104
|
+
loAppOrigin: this.getEnv().loAppOrigin,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
CLIENT_ERROR_TYPES,
|
|
9
|
+
onError,
|
|
10
|
+
onHttpError,
|
|
11
|
+
onInvalidSession,
|
|
12
|
+
onUnhandledRejection,
|
|
13
|
+
} from "@lwrjs/globalErrorHandler";
|
|
14
|
+
|
|
15
|
+
export function createErrorHooks(parentPostMessage, logError) {
|
|
16
|
+
function post(type, payload) {
|
|
17
|
+
parentPostMessage({ type: "lo.error", error: { ...payload, type } });
|
|
18
|
+
logError(payload);
|
|
19
|
+
return { handled: true };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onError((error, type) => post(type, { message: `Error: ${error.message}` }));
|
|
23
|
+
onUnhandledRejection((error, type) =>
|
|
24
|
+
post(type, {
|
|
25
|
+
message: `Unhandled Promise Rejection: ${error.message}`,
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
onInvalidSession((error, type) => post(type, { message: `Invalid Session: ${error.message}` }));
|
|
29
|
+
onHttpError((error, type) => {
|
|
30
|
+
if (type === CLIENT_ERROR_TYPES.HTTP_ERROR) {
|
|
31
|
+
const status = error.status || (error.response && error.response.status);
|
|
32
|
+
if (status) {
|
|
33
|
+
let message = "";
|
|
34
|
+
switch (status) {
|
|
35
|
+
case 401:
|
|
36
|
+
message = "Session expired or unauthorized. Please log in again.";
|
|
37
|
+
break;
|
|
38
|
+
case 429:
|
|
39
|
+
message = "Too many requests. Please try again later.";
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
if (status >= 500) {
|
|
43
|
+
message = "A server error occurred. Please try again later.";
|
|
44
|
+
}
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
return post(type, {
|
|
48
|
+
status,
|
|
49
|
+
message: `HTTP Error: ${message}`,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return { handled: false };
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import disableBeaconGate from "@salesforce/gate/org.salesforce.lo2.lwr.disableBeacon";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @returns {boolean} Checks if the beacon feature is enabled.
|
|
11
|
+
*/
|
|
12
|
+
export function isBeaconEnabled() {
|
|
13
|
+
return !disableBeaconGate.isOpen({ fallback: false });
|
|
14
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
3
|
+
<isExposed>true</isExposed>
|
|
4
|
+
<targets>
|
|
5
|
+
<target>lightningCommunity__Page</target>
|
|
6
|
+
<target>lightningCommunity__Default</target>
|
|
7
|
+
</targets>
|
|
8
|
+
</LightningComponentBundle>
|
package/dist/modules/force/lightningOutOneRuntimeContainer/lightningOutOneRuntimeContainer.html
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<template lwc:render-mode="light">
|
|
2
|
+
<div lwc:if={includeBeacon}>
|
|
3
|
+
<aura-interop
|
|
4
|
+
descriptor="instrumentation:beacon"
|
|
5
|
+
config={config}
|
|
6
|
+
></aura-interop>
|
|
7
|
+
</div>
|
|
8
|
+
<lwrlex-instrumentation></lwrlex-instrumentation>
|
|
9
|
+
<lwc:component
|
|
10
|
+
lwc:is={embeddedCmpCtor}
|
|
11
|
+
lwc:ref="embeddedCmp"
|
|
12
|
+
lwc:spread={embeddedCmpProps}
|
|
13
|
+
></lwc:component>
|
|
14
|
+
</template>
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import LightningOutBaseContainer from "force/lightningOutBaseContainer";
|
|
8
|
+
|
|
9
|
+
import { createErrorHooks } from "./utils/errorHandling";
|
|
10
|
+
import { isBeaconEnabled } from "./utils/gater";
|
|
11
|
+
|
|
12
|
+
export default class LightningOutOneRuntimeContainer extends LightningOutBaseContainer {
|
|
13
|
+
#includeBeacon = false;
|
|
14
|
+
config = {
|
|
15
|
+
usePageTransactions: false,
|
|
16
|
+
disableAvroValidation: false,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
constructor() {
|
|
20
|
+
super();
|
|
21
|
+
createErrorHooks(this.getEnv().parentPostMessage, this.getInstrumentation().logError);
|
|
22
|
+
this.#includeBeacon = isBeaconEnabled();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
get includeBeacon() {
|
|
26
|
+
return this.#includeBeacon;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
resolveEmbeddedCmpSpecifier(embeddedCmpName) {
|
|
30
|
+
const [name, version] = embeddedCmpName.split("/v/");
|
|
31
|
+
const type = name.includes(":") ? "aura" : "lwc";
|
|
32
|
+
const calculatedVersion = version || "0_0_1";
|
|
33
|
+
if (type === "aura") {
|
|
34
|
+
return { specifier: `aura/interop/v/${calculatedVersion}`, type };
|
|
35
|
+
}
|
|
36
|
+
return { specifier: `${name}/v/${calculatedVersion}`, type };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
CLIENT_ERROR_TYPES,
|
|
9
|
+
onError,
|
|
10
|
+
onHttpError,
|
|
11
|
+
onInvalidSession,
|
|
12
|
+
onUnhandledRejection,
|
|
13
|
+
} from "@lwrjs/globalErrorHandler";
|
|
14
|
+
|
|
15
|
+
export function createErrorHooks(parentPostMessage, logError) {
|
|
16
|
+
function post(type, payload) {
|
|
17
|
+
parentPostMessage({ type: "lo.error", error: { ...payload, type } });
|
|
18
|
+
logError(payload);
|
|
19
|
+
return { handled: true };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
onError((error, type) => post(type, { message: `Error: ${error.message}` }));
|
|
23
|
+
onUnhandledRejection((error, type) =>
|
|
24
|
+
post(type, {
|
|
25
|
+
message: `Unhandled Promise Rejection: ${error.message}`,
|
|
26
|
+
}),
|
|
27
|
+
);
|
|
28
|
+
onInvalidSession((error, type) => post(type, { message: `Invalid Session: ${error.message}` }));
|
|
29
|
+
onHttpError((error, type) => {
|
|
30
|
+
if (type === CLIENT_ERROR_TYPES.HTTP_ERROR) {
|
|
31
|
+
const status = error.status || (error.response && error.response.status);
|
|
32
|
+
if (status) {
|
|
33
|
+
let message = "";
|
|
34
|
+
if (status === 401) {
|
|
35
|
+
message = "Session expired or unauthorized. Please log in again.";
|
|
36
|
+
} else if (status === 429) {
|
|
37
|
+
message = "Too many requests. Please try again later.";
|
|
38
|
+
} else if (status >= 500) {
|
|
39
|
+
message = "A server error occurred. Please try again later.";
|
|
40
|
+
}
|
|
41
|
+
return post(type, {
|
|
42
|
+
status,
|
|
43
|
+
message: `HTTP Error: ${message}`,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return { handled: false };
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2025 salesforce.com, inc.
|
|
3
|
+
* All Rights Reserved
|
|
4
|
+
* Company Confidential
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import disableBeaconGate from "@salesforce/gate/org.salesforce.lo2.lwr.disableBeacon";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @returns {boolean} Checks if the beacon feature is enabled.
|
|
11
|
+
*/
|
|
12
|
+
export function isBeaconEnabled() {
|
|
13
|
+
return !disableBeaconGate.isOpen({ fallback: false });
|
|
14
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lightning-out/containers",
|
|
3
|
+
"version": "2.2.0-rc.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Lightning Out 2.0 Container Components",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "node scripts/build.mjs",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"clean": "rimraf dist"
|
|
14
|
+
},
|
|
15
|
+
"publishConfig": {
|
|
16
|
+
"access": "public"
|
|
17
|
+
}
|
|
18
|
+
}
|