@salesforce/afv-skills 1.56.0 → 1.58.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.
Files changed (65) hide show
  1. package/package.json +1 -1
  2. package/skills/commerce-b2b-open-code-components-integrate/SKILL.md +1 -1
  3. package/skills/commerce-b2b-open-code-components-replace/SKILL.md +16 -16
  4. package/skills/dx-devops-project-manage/SKILL.md +1 -1
  5. package/skills/experience-cms-content-generate/SKILL.md +1 -1
  6. package/skills/experience-cms-content-render/SKILL.md +3 -3
  7. package/skills/experience-cms-content-render/assets/angular/MediaRenderer.component.ts +35 -7
  8. package/skills/experience-cms-content-render/assets/angular/cms-item.service.ts +13 -4
  9. package/skills/experience-cms-content-render/assets/react/MediaRenderer.tsx +30 -8
  10. package/skills/experience-cms-content-render/assets/react/useCmsItem.ts +14 -4
  11. package/skills/experience-cms-content-render/assets/shared/cmsCore.types.ts +11 -1
  12. package/skills/experience-cms-content-render/assets/shared/externalRefs.ts +1 -1
  13. package/skills/experience-cms-content-render/assets/shared/mediaLabels.ts +62 -0
  14. package/skills/experience-cms-content-render/references/init-scaffold.md +13 -6
  15. package/skills/experience-content-media-stock-image-search/SKILL.md +0 -1
  16. package/skills/experience-lwc-design-generate/SKILL.md +1 -1
  17. package/skills/experience-lwc-legacy-migrate/SKILL.md +212 -0
  18. package/skills/experience-lwc-legacy-migrate/assets/lo20-host-page-template.html +192 -0
  19. package/skills/experience-lwc-legacy-migrate/references/aura-to-lwc-completeness-checklist.md +188 -0
  20. package/skills/experience-lwc-legacy-migrate/references/lightning-out-2-system-reference.md +495 -0
  21. package/skills/experience-lwc-legacy-migrate/references/lightning-out-beta-to-2-migration.md +824 -0
  22. package/skills/experience-lwc-legacy-migrate/scripts/convert-lo-names.py +94 -0
  23. package/skills/experience-lwc-legacy-migrate/scripts/validate-lo20-page.py +133 -0
  24. package/skills/experience-ui-bundle-project-generate/SKILL.md +14 -40
  25. package/skills/experience-ui-bundle-project-generate/scripts/flatten-project.mjs +33 -11
  26. package/skills/experience-ui-bundle-project-generate/scripts/generate-project.mjs +77 -0
  27. package/skills/experience-ui-bundle-project-generate/scripts/install-deps.mjs +95 -0
  28. package/skills/integration-connectivity-connected-app-configure/SKILL.md +5 -5
  29. package/skills/integration-connectivity-generate/SKILL.md +10 -10
  30. package/skills/integration-connectivity-generate/scripts/configure-named-credential.sh +2 -2
  31. package/skills/platform-apex-test-generate/SKILL.md +1 -1
  32. package/skills/platform-apex-test-run/SKILL.md +1 -1
  33. package/skills/platform-custom-field-generate/SKILL.md +1 -1
  34. package/skills/platform-custom-lightning-type-generate/SKILL.md +1 -1
  35. package/skills/platform-custom-metadata-type-generate/SKILL.md +1 -1
  36. package/skills/platform-custom-object-generate/SKILL.md +1 -1
  37. package/skills/platform-custom-report-type-generate/SKILL.md +1 -1
  38. package/skills/platform-custom-setting-generate/SKILL.md +1 -1
  39. package/skills/platform-data-and-tooling-api-context-get/SKILL.md +1 -1
  40. package/skills/platform-data-manage/SKILL.md +10 -10
  41. package/skills/platform-flexipage-generate/SKILL.md +1 -1
  42. package/skills/platform-lightning-app-coordinate/SKILL.md +1 -1
  43. package/skills/platform-metadata-api-context-get/SKILL.md +1 -1
  44. package/skills/platform-metadata-retrieve/SKILL.md +1 -1
  45. package/skills/platform-permission-set-generate/SKILL.md +1 -1
  46. package/skills/platform-report-generate/SKILL.md +1 -1
  47. package/skills/platform-salesforce-connect-adapter-generate/SKILL.md +4 -4
  48. package/skills/platform-sharing-owd-configure/SKILL.md +1 -1
  49. package/skills/platform-sharing-rules-generate/SKILL.md +1 -1
  50. package/skills/platform-soql-query/SKILL.md +1 -1
  51. package/skills/platform-value-set-generate/SKILL.md +1 -1
  52. package/skills/service-agentforce-human-escalation-configure/SKILL.md +4 -0
  53. package/skills/service-agentforce-human-escalation-configure/scripts/tests/_bootstrap.py +26 -6
  54. package/skills/service-agentforce-human-escalation-configure/scripts/tests/test_escalation_contracts.py +5 -4
  55. package/skills/service-de-waba-integrate/SKILL.md +2 -1
  56. package/skills/service-digital-engagement-deployment-configure/SKILL.md +2 -0
  57. package/skills/service-digital-engagement-deployment-configure/scripts/check-api-version.sh +29 -0
  58. package/skills/service-email-to-case-configure/SKILL.md +1 -1
  59. package/skills/service-omni-channel-setup-coordinate/SKILL.md +1 -0
  60. package/skills/service-omni-command-center-analyze/SKILL.md +1 -0
  61. package/skills/service-omni-command-center-configure/SKILL.md +92 -0
  62. package/skills/service-omni-command-center-configure/references/api-notes.md +50 -0
  63. package/skills/service-omni-command-center-configure/scripts/configure-and-report.sh +257 -0
  64. package/skills/service-omni-command-center-configure/scripts/settings_document.py +97 -0
  65. package/skills/service-omni-command-center-configure/scripts/tests/test_command_center_configure_contracts.py +206 -0
@@ -0,0 +1,495 @@
1
+ Lightning Out 2.0 is **not** a simple library upgrade. It is an entirely different embedding paradigm built on Web Components and iframes. This reference captures the essential architecture, constraints, and mental model.
2
+
3
+ ---
4
+
5
+ ### 1. Foundational Mental Model
6
+
7
+ #### Core Principle: Dual-Context Architecture
8
+
9
+ LO 2.0 creates a **two-world system** on every host page:
10
+
11
+ | Context | Runs on | Contains | Controlled by |
12
+ | ---------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------- | ------------------ |
13
+ | **Host page context** | The external (non-Salesforce) page | LO 2.0 web components (shells), the `lightning-out-application` element, host page JS | The developer |
14
+ | **Salesforce context** | Inside iframes within closed shadow DOMs | The actual LWC components, Salesforce platform services (LDS, Apex, etc.) | Salesforce runtime |
15
+
16
+ **Why this matters for migration**: In Lightning Out Beta, the LWC ran directly on the host page via `$Lightning.createComponent()`. In LO 2.0, the LWC is isolated inside an iframe. This means:
17
+
18
+ - Host page JavaScript **cannot** directly access DOM inside the LWC.
19
+ - The LWC **cannot** directly access host page DOM.
20
+ - Communication must go through the event bridge (see Section 5).
21
+ - CSS from the host page does **not** cascade into the iframe (see Section 4).
22
+
23
+ #### The Three Pillars of a LO 2.0 App
24
+
25
+ Every LO 2.0 app on a host page consists of exactly three elements:
26
+
27
+ 1. **The LO 2.0 JavaScript library** — A `<script>` tag that loads the LO 2.0 runtime, which registers the custom elements.
28
+ 2. **The `<lightning-out-application>` element** — A non-visual web component that holds the app configuration (auth, optional app ID, component list). There should be **exactly one** per app.
29
+ 3. **One or more LO 2.0 web component shells** — Elements like `<c-my-component>` that mirror the embedded LWC components. Each shell contains an iframe with a closed shadow DOM root.
30
+
31
+ ```text
32
+ Host Page
33
+ ├── <script src="...lightning.out.latest/index.iife.prod.js">
34
+ ├── <lightning-out-application app-id="..." frontdoor-url="..." components="c-my-comp">
35
+ └── <c-my-comp style="--custom-color: blue;">
36
+ └── #shadow-root (closed)
37
+ └── <iframe>
38
+ └── <html> (Salesforce context)
39
+ └── <body>
40
+ └── <c-my-comp style="--custom-color: blue;"> ← actual LWC
41
+ ```
42
+
43
+ ---
44
+
45
+ ### 2. Initialization Lifecycle (Exact Sequence)
46
+
47
+ Understanding the initialization order is critical for writing correct mount and readiness code.
48
+
49
+ #### Step-by-Step Flow
50
+
51
+ 1. **End user opens host page** — The host page HTML loads.
52
+ 2. **LO 2.0 library script loads** (async) — Registers `lightning-out-application` and other custom elements with the browser's `customElements` registry.
53
+ 3. **Host page obtains a frontdoor URL** — Via the UI Bridge API, exchanging a Salesforce access token or Session ID. If the user is not authenticated, an OAuth flow (PKCE) is triggered first.
54
+ 4. **Host page sets `frontdoor-url`** on `<lightning-out-application>` — This is done programmatically at runtime. The element must already have `components` set (and optionally `app-id`, if the app requires it).
55
+ 5. **LO 2.0 establishes a session** using the frontdoor URL — The `lightning-out-application` element initiates a Salesforce session.
56
+ 6. **`lo.application.ready` fires** — Indicates the Salesforce session was established successfully.
57
+ 7. **LO 2.0 web component shells initialize** — Each shell creates an iframe that becomes the root of a closed shadow DOM.
58
+ 8. **Inside the iframes, the actual LWC components initialize** — They run in the Salesforce context with full platform access.
59
+ 9. **`lo.component.ready` fires** — Indicates the component rendered successfully inside its iframe.
60
+
61
+ #### Error Events
62
+
63
+ - **`lo.application.error`** — Session establishment failed. Has `detail.message` and `detail.originalError`.
64
+ - **`lo.component.error`** — Component render failed or runtime error in the LWC. Same detail structure.
65
+
66
+ #### Key Timing Implications
67
+
68
+ - The LO 2.0 library loads **asynchronously**. The `lightning-out-application` custom element may not be registered when your script runs. You **must** poll `customElements.get('lightning-out-application')` before creating/appending the element.
69
+ - The `frontdoor-url` attribute **must** be set dynamically at runtime. It cannot be hardcoded in HTML (the URL is session-specific and short-lived).
70
+ - Component readiness can be detected via `customElements.whenDefined('c-my-component')` — but the argument **must be a string literal**, not a variable (browsers resolve this at parse time in some implementations, and LO 2.0's internal custom element registration relies on the literal name).
71
+
72
+ ---
73
+
74
+ ### 3. Authentication Model
75
+
76
+ #### Beta vs. 2.0 Authentication
77
+
78
+ | Aspect | Lightning Out Beta | Lightning Out 2.0 |
79
+ | ---------------- | ---------------------------------------------------- | -------------------------------------------------------------- |
80
+ | Auth mechanism | Hardcoded session token passed to `$Lightning.use()` | OAuth 2.0 PKCE flow → frontdoor URL |
81
+ | Token location | In JavaScript source (insecure) | Never exposed in source; exchanged via UI Bridge API |
82
+ | Session init | `$Lightning.use(app, callback, endpoint, token)` | Set `frontdoor-url` attribute on `<lightning-out-application>` |
83
+ | User requirement | Authenticated Salesforce user | Authenticated Salesforce user (unauthenticated not supported) |
84
+
85
+ #### OAuth 2.0 PKCE Flow in LO 2.0
86
+
87
+ The typical flow involves:
88
+
89
+ 1. Store OAuth config in `localStorage` (`orgMyDomainURL`, `loAppID`, `loECAKey`, `lo2_returnTo`).
90
+ 2. Redirect user to OAuth callback page (e.g., `/frontdoor-url.html`).
91
+ 3. Callback page completes PKCE, obtains frontdoor URL.
92
+ 4. Callback page communicates the frontdoor URL back to the host page via **three redundant channels**:
93
+ - `window.postMessage()` — For same-window communication.
94
+ - `BroadcastChannel('lo2auth')` — For same-origin, cross-tab communication.
95
+ - `localStorage` event (`lo2_frontdoor_result`) — Fallback for cross-tab communication.
96
+
97
+ #### Why Three Channels?
98
+
99
+ Browser support and tab lifecycle vary. `postMessage` works when the callback is in the same tab. `BroadcastChannel` works cross-tab but isn't supported everywhere. The `storage` event is the most broadly supported cross-tab mechanism. Listening on all three ensures reliable auth completion.
100
+
101
+ #### Constraint: No Client Credentials Flow
102
+
103
+ LO 2.0 does not support OAuth 2.0 client credentials flow because that flow lacks user context. Every LO 2.0 session requires an authenticated Salesforce user identity.
104
+
105
+ ---
106
+
107
+ ### 4. Styling System — What Crosses the iframe Boundary
108
+
109
+ #### The Fundamental Rule
110
+
111
+ **Only CSS custom properties (variables with `--` prefix) cross from the host page into the iframe.** Standard CSS properties like `font-size`, `background-color`, `font-family` are **blocked** at the iframe boundary.
112
+
113
+ #### What Works
114
+
115
+ - SLDS 1 styling hooks: `--slds-c-card-color-background`, `--slds-c-card-text-color`, etc.
116
+ - SLDS 2 global styling hooks: `--slds-g-color-brand-base-30`, `--slds-g-font-scale-3`, etc.
117
+ - Custom CSS properties: `--custom-color`, `--my-app-spacing`, etc.
118
+ - CSS custom property values with `var()` fallbacks: `var(--slds-g-color-brand-base-30, #022ac0)`.
119
+
120
+ #### What Does NOT Work
121
+
122
+ - Direct CSS properties: `font-family: cursive` — **will be ignored**.
123
+ - Direct CSS properties: `font-size: 120%` — **will be ignored**.
124
+ - Any standard CSS property that is not a custom property (no `--` prefix).
125
+
126
+ #### How to Style LO 2.0 Components
127
+
128
+ 1. **In the LWC's CSS file**, declare CSS custom properties on `:host` and reference them in rules:
129
+ ```css
130
+ :host {
131
+ --custom-color: #b50be3;
132
+ }
133
+ h1 {
134
+ color: var(--custom-color);
135
+ }
136
+ ```
137
+ 2. **On the host page**, override the custom properties via the `style` attribute:
138
+ ```html
139
+ <c-my-comp style="--custom-color: #8c23a8;"></c-my-comp>
140
+ ```
141
+ 3. Properties can also be set via JSON in the Lightning Out 2.0 App Manager or programmatically via `setAttribute('style', ...)`.
142
+
143
+ #### Supported Standard Attributes
144
+
145
+ These standard HTML attributes **are** passed through to the LWC:
146
+ `autocapitalize`, `autocorrect`, `dir`, `enterkeyhint`, `inputmode`, `lang`, `spellcheck`, `title`, `translate`.
147
+
148
+ #### Supported ARIA Attributes
149
+
150
+ `aria-disabled`, `aria-hidden`, `aria-label`, `aria-live`, `aria-modal`, `aria-pressed`, `aria-valuemax`, `aria-valuemin`, `aria-valuenow`.
151
+
152
+ #### Blocked Standard Attributes
153
+
154
+ These are **NOT** passed through:
155
+ `accesskey`, `autofocus`, `draggable`, `exportparts`, `hidden`, `inert`, `nonce`, `part`, `slot`, `tabindex`.
156
+
157
+ #### Blocked ARIA Attributes (Reference-Based)
158
+
159
+ These ARIA attributes that reference other elements by ID are blocked because IDs don't cross iframe boundaries:
160
+ `aria-activedescendant`, `aria-controls`, `aria-describedby`, `aria-details`, `aria-errormessage`, `aria-flowto`, `aria-labelledby`, `aria-owns`.
161
+
162
+ #### Custom Attributes
163
+
164
+ All custom `@api` properties exposed on the LWC are supported as HTML attributes on the LO 2.0 shell — **unless the attribute name starts with an underscore** (`_`). Attributes are passed in kebab-case (e.g., LWC property `cardBody` → HTML attribute `card-body`).
165
+
166
+ Passing an unsupported attribute silently does nothing — no compilation or runtime error is raised.
167
+
168
+ ---
169
+
170
+ ### 5. Event System — Cross-iframe Communication
171
+
172
+ #### How It Works Internally
173
+
174
+ LO 2.0 uses `window.postMessage()` under the hood to bridge events across the iframe boundary. However, from the developer's perspective, the standard `EventTarget` and `CustomEvent` APIs are used directly.
175
+
176
+ #### Event Mirroring
177
+
178
+ The LO 2.0 web component shell on the host page **mirrors** the embedded LWC component in the iframe. This mirroring extends to events:
179
+
180
+ - **Adding a listener** on the shell also adds it on the LWC inside the iframe.
181
+ - **Dispatching an event** on the shell also dispatches it on the LWC inside the iframe.
182
+ - Events dispatched **inside the LWC** bubble up to the shell on the host page.
183
+ - Events dispatched **on the shell** propagate down to the LWC inside the iframe.
184
+
185
+ #### Required Event Configuration
186
+
187
+ Custom events that need to cross the iframe boundary **must** set:
188
+
189
+ ```javascript
190
+ new CustomEvent('myEvent', {
191
+ detail: {
192
+ /* payload */
193
+ },
194
+ bubbles: true, // Required: to cross shadow DOM boundary
195
+ composed: true, // Required: to cross shadow DOM boundary
196
+ });
197
+ ```
198
+
199
+ Without `bubbles: true` and `composed: true`, the event will not pass through the closed shadow DOM.
200
+
201
+ #### Host Page → LWC Communication
202
+
203
+ ```javascript
204
+ // On the host page:
205
+ const loComponent = document.querySelector('c-my-component');
206
+ loComponent.dispatchEvent(
207
+ new CustomEvent('sendMessageToLWC', {
208
+ detail: { message: 'Hello from host' },
209
+ bubbles: true,
210
+ composed: true,
211
+ }),
212
+ );
213
+ ```
214
+
215
+ ```javascript
216
+ // In the LWC (connectedCallback):
217
+ this.addEventListener('sendMessageToLWC', this.handleMessage);
218
+ ```
219
+
220
+ #### LWC → Host Page Communication
221
+
222
+ ```javascript
223
+ // In the LWC:
224
+ this.dispatchEvent(
225
+ new CustomEvent('lwcMessageToHost', {
226
+ detail: { message: 'Hello from LWC' },
227
+ bubbles: true,
228
+ composed: true,
229
+ }),
230
+ );
231
+ ```
232
+
233
+ ```javascript
234
+ // On the host page:
235
+ const loComponent = document.querySelector('c-my-component');
236
+ loComponent.addEventListener('lwcMessageToHost', (event) => {
237
+ console.log(event.detail.message);
238
+ });
239
+ ```
240
+
241
+ #### Timing Consideration
242
+
243
+ Set event listeners on the LO 2.0 shell component **after** the application and component have loaded. For example, conditionally set listeners after the `frontdoor-url` attribute is set or after `lo.component.ready` fires.
244
+
245
+ ---
246
+
247
+ ### 6. Hard Constraints & Limitations
248
+
249
+ These are non-negotiable platform boundaries. No workaround exists for these limitations.
250
+
251
+ #### Component Constraints
252
+
253
+ - **Only custom LWC components** can be embedded. Standard LWC components (`lightning-button`, `lightning-card`, etc.) must be **wrapped** inside a custom LWC. Even when wrapped, they may not be fully styled or behave as documented.
254
+ - **No Aura components** — Neither custom nor standard Aura components are supported. This includes Aura apps — the `c:OrgFarmOut` Aura app pattern from Beta is replaced by the `app-id` attribute.
255
+ - **No `lightning/navigation`** — Page navigation within embedded components is not supported.
256
+
257
+ #### Security & Cookie Constraints
258
+
259
+ - **Third-party cookies required** — End users must have third-party (cross-origin) cookies enabled in their browser. Cross-domain Salesforce session cookies must also be enabled in the org.
260
+ - **No LO 2.0 library loading from LWC** — Lightning Web Security (LWS) blocks insertion of `<script>` elements. The library must be loaded from the host page directly.
261
+
262
+ #### Authentication Constraints
263
+
264
+ - **Authenticated users only** — Unauthenticated access is not supported.
265
+ - **No client credentials flow** — Requires user context (PKCE or session-based).
266
+
267
+ #### Style Constraints (Summary)
268
+
269
+ - Only CSS custom properties (`--` prefix) cross the iframe boundary.
270
+ - Standard CSS properties set on the shell are NOT applied inside the iframe.
271
+ - Blocked attributes (see Section 4) silently fail — no error raised.
272
+
273
+ ---
274
+
275
+ ### 7. Component Naming Conventions
276
+
277
+ #### Conversion from Aura to LO 2.0
278
+
279
+ Aura components use the `namespace:componentName` format. LO 2.0 uses kebab-case web component format.
280
+
281
+ **Algorithm:**
282
+
283
+ 1. Remove `c:` prefix.
284
+ 2. Insert hyphen before each uppercase letter.
285
+ 3. Convert entire string to lowercase.
286
+ 4. Add `c-` prefix.
287
+
288
+ **Examples:**
289
+ | Aura Format | LO 2.0 Kebab-Case |
290
+ |---|---|
291
+ | `c:myComponent` | `c-my-component` |
292
+ | `c:loBetaEntryForm` | `c-lo-beta-entry-form` |
293
+ | `c:userDashboard` | `c-user-dashboard` |
294
+
295
+ **Mixed-case namespaces** use underscores to separate namespace parts:
296
+ | Namespace/Component | LO 2.0 Format |
297
+ |---|---|
298
+ | `complexNs/lwcComponent` | `complex_ns-lwc-component` |
299
+
300
+ #### Attribute Name Conversion
301
+
302
+ LWC `@api` properties in camelCase become kebab-case HTML attributes:
303
+ | LWC Property | HTML Attribute |
304
+ |---|---|
305
+ | `contactId` | `contact-id` |
306
+ | `recordId` | `record-id` |
307
+ | `isActive` | `is-active` |
308
+
309
+ ---
310
+
311
+ ### 8. Domain Transformation Rules
312
+
313
+ The Salesforce domain format changes between Beta and 2.0:
314
+
315
+ | Component | Beta | 2.0 |
316
+ | -------------- | ----------------------------------------------- | ---------------------------------------------------- |
317
+ | Domain suffix | `.lightning.force.com` | `.my.salesforce.com` |
318
+ | Full pattern | `https://[subdomain].lightning.[pod].force.com` | `https://[subdomain].my.[pod].salesforce.com` |
319
+ | Library path | `/lightning/lightning.out.js` | `/lightning/lightning.out.latest/index.iife.prod.js` |
320
+ | Script loading | `<script src="...">` | `<script async src="...">` (note: `async` attribute) |
321
+
322
+ **Example transformation:**
323
+
324
+ ```text
325
+ Beta: https://orgfarm-5b43fe90c6.test1.lightning.pc-rnd.force.com
326
+ LO 2.0: https://orgfarm-5b43fe90c6.test1.my.pc-rnd.salesforce.com
327
+ ```
328
+
329
+ ---
330
+
331
+ ### 9. Configuration Methods for Component Properties
332
+
333
+ LO 2.0 supports three ways to set component properties:
334
+
335
+ #### A. Declarative (HTML)
336
+
337
+ Set attributes directly on the LO 2.0 web component shell in the host page HTML:
338
+
339
+ ```html
340
+ <c-my-comp style="--slds-c-card-color-background: var(--secondary-color);" card-body="Custom text"></c-my-comp>
341
+ ```
342
+
343
+ #### B. Programmatic (JavaScript)
344
+
345
+ Use DOM API methods to create and configure the component:
346
+
347
+ ```javascript
348
+ const comp = document.createElement('c-my-comp');
349
+ comp.setAttribute('style', '--custom-color: blue;');
350
+ comp.setAttribute('card-body', 'Custom text');
351
+ document.body.appendChild(comp);
352
+ ```
353
+
354
+ #### C. App Manager (Setup UI)
355
+
356
+ In the Lightning Out 2.0 App Manager, properties are set as a JSON object on each component:
357
+
358
+ ```json
359
+ {
360
+ "style": "--slds-c-card-color-background: #ccc; --custom-color: blue;",
361
+ "card-body": "Custom text"
362
+ }
363
+ ```
364
+
365
+ All three methods produce the same result: attributes on the LO 2.0 shell are mirrored to the LWC inside the iframe.
366
+
367
+ ---
368
+
369
+ ### 10. Critical Patterns for Correct Migration Code
370
+
371
+ These patterns are derived from real migration failures and represent hard requirements for a working LO 2.0 host page.
372
+
373
+ #### Pattern 1: The `boot()` Wrapper
374
+
375
+ All initialization logic MUST be wrapped in a single `boot()` function called at the end of the script. Do NOT split initialization into separate functions like `initializeOAuth()` and `setupCallbackListeners()`.
376
+
377
+ **Why**: Consolidating init in `boot()` ensures a single error boundary, predictable execution order, and a clear entry point. Splitting it risks partial initialization on error.
378
+
379
+ #### Pattern 2: `customElements.whenDefined()` Requires a String Literal
380
+
381
+ ```javascript
382
+ // WRONG — will silently fail or behave unpredictably
383
+ const components = "c-my-component";
384
+ customElements.whenDefined(components).then(() => { ... });
385
+
386
+ // CORRECT — use the literal string directly
387
+ customElements.whenDefined('c-my-component').then(() => { ... });
388
+ ```
389
+
390
+ **Why**: The browser's custom elements API and LO 2.0's internal registration can behave differently when a variable is passed vs. a literal. Always use the literal.
391
+
392
+ #### Pattern 3: `mountLo20()` Must Accept Two Parameters
393
+
394
+ ```javascript
395
+ function mountLo20(frontdoorUrl, orgUrl) { ... }
396
+ ```
397
+
398
+ **Why**: All three OAuth callback channels (`postMessage`, `BroadcastChannel`, `storage`) may pass both `frontdoorUrl` and `orgUrl`. Even if `orgUrl` is unused, the function signature must match what callers pass.
399
+
400
+ #### Pattern 4: Always `clearCachedResult()` Before Mounting
401
+
402
+ ```javascript
403
+ clearCachedResult();
404
+ mountLo20(data.frontdoorUrl, data.orgUrl);
405
+ ```
406
+
407
+ **Why**: Stale cache entries can cause duplicate mounts or auth loops. Clear before every mount call.
408
+
409
+ #### Pattern 5: Validate Data in Every Listener
410
+
411
+ Every OAuth callback listener must check three conditions:
412
+
413
+ ```javascript
414
+ if (!data) return; // No data at all
415
+ if (data.error) return showError(...); // Auth error
416
+ if (!data.frontdoorUrl) return; // Incomplete data
417
+ ```
418
+
419
+ #### Pattern 6: No Inline `display: none` on Component Tags
420
+
421
+ ```html
422
+ <!-- WRONG -->
423
+ <c-my-component style="display: none"></c-my-component>
424
+
425
+ <!-- CORRECT -->
426
+ <c-my-component></c-my-component>
427
+ ```
428
+
429
+ **Why**: LO 2.0 initializes the component shell and its iframe. Adding `display: none` directly on the component tag can interfere with this initialization. Instead, control visibility through a separate loading element.
430
+
431
+ #### Pattern 7: Wrap `BroadcastChannel` in try-catch
432
+
433
+ ```javascript
434
+ try {
435
+ const bc = new BroadcastChannel('lo2auth');
436
+ bc.onmessage = (evt) => { ... };
437
+ } catch (e) {
438
+ // Not supported in all browsers
439
+ }
440
+ ```
441
+
442
+ #### Pattern 8: Poll for Custom Element Registration
443
+
444
+ The LO 2.0 library loads asynchronously. Before creating `lightning-out-application`, you must poll:
445
+
446
+ ```javascript
447
+ function tryMount() {
448
+ if (!customElements?.get?.('lightning-out-application')) return false;
449
+ // ... create and append the element
450
+ return true;
451
+ }
452
+
453
+ const start = Date.now();
454
+ (function tick() {
455
+ if (tryMount()) return;
456
+ if (Date.now() - start > 15000) {
457
+ showError('Timeout');
458
+ return;
459
+ }
460
+ setTimeout(tick, 50);
461
+ })();
462
+ ```
463
+
464
+ ---
465
+
466
+ ### 11. What Changes During Migration (Summary)
467
+
468
+ | Aspect | Lightning Out Beta | Lightning Out 2.0 |
469
+ | ------------------- | ---------------------------------------------------------- | ---------------------------------------------------------------------- |
470
+ | Library URL | `.lightning.force.com/lightning/lightning.out.js` | `.my.salesforce.com/lightning/lightning.out.latest/index.iife.prod.js` |
471
+ | Script loading | Synchronous | Asynchronous (`async` attribute) |
472
+ | App reference | Aura app name (`c:OrgFarmOut`) | Optional 18-character App ID from Setup |
473
+ | Component naming | Aura format (`c:myComponent`) | Kebab-case (`c-my-component`) |
474
+ | Component init | `$Lightning.createComponent(name, attrs, domId, callback)` | Declarative HTML tag + `<lightning-out-application>` |
475
+ | Attributes | JavaScript object passed to `createComponent` | HTML attributes in kebab-case on the component tag |
476
+ | Readiness | Callback parameter in `createComponent` | `customElements.whenDefined('c-my-component')` |
477
+ | Auth | Hardcoded token in `$Lightning.use()` | OAuth PKCE → frontdoor URL set at runtime |
478
+ | Component isolation | Runs directly on host page | Runs inside iframe within closed shadow DOM |
479
+ | DOM access | Host JS can access component DOM | Host JS **cannot** access component DOM |
480
+ | CSS inheritance | Host page CSS cascades to component | **Only** CSS custom properties cross the boundary |
481
+ | Event communication | Direct DOM events | Mirrored events bridged via `postMessage` internally |
482
+
483
+ ---
484
+
485
+ ### 12. What to Preserve During Migration
486
+
487
+ When migrating a host page, the following elements from the original page **must be preserved**:
488
+
489
+ 1. **HTML structure** — Layout, hierarchy, and element order. Don't restructure.
490
+ 2. **Existing CSS and classes** — All host page styling remains unchanged.
491
+ 3. **Loading indicators** — Hook into existing UI elements; don't create new ones.
492
+ 4. **Error display mechanisms** — Use the page's existing error handling.
493
+ 5. **Event handlers on non-LO elements** — Any click handlers, form logic, etc.
494
+ 6. **Business logic from Beta callbacks** — Move callback logic from `$Lightning.createComponent`'s callback to `customElements.whenDefined().then()`.
495
+ 7. **Element IDs and selectors** — Use the page's actual IDs, not template defaults.