From 96e45a28c6f93cb630ec24436ac2b7f9d233d145 Mon Sep 17 00:00:00 2001 From: akashdhake Date: Thu, 15 Oct 2026 18:38:22 +0530 Subject: [PATCH 1/3] feat(lightning-out): @W-24501804@ promote command to GA and polish success messages Remove the beta state and hidden flag so the command appears in help, docs and autocomplete and no longer prints the beta banner. Also replace em dashes in the success.app-id and success.dont-delete messages and use 'Lightning Out 2.0' consistently in the success text. --- messages/lightningOut.md | 6 +++--- src/commands/template/generate/lightning-out/index.ts | 2 -- test/commands/template/generate/lightning-out/index.test.ts | 6 +++--- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/messages/lightningOut.md b/messages/lightningOut.md index a0e64938..1aff0c86 100644 --- a/messages/lightningOut.md +++ b/messages/lightningOut.md @@ -86,11 +86,11 @@ Scaffold generated in %s. Deploy it with: sf project deploy start --source-dir % # success.app-id -After deploying, note the LightningOutApp's App ID from Setup — your host page needs it to embed the app. +After deploying, note the LightningOutApp's App ID from Setup; your host page needs it to embed the app. # success.dont-delete -Don't delete the generated ExternalClientApplication after deploying — Lightning Out uses it for OAuth at runtime. +Don't delete the generated ExternalClientApplication after deploying. Lightning Out 2.0 uses it for OAuth at runtime. # success.eca-overwrite @@ -98,7 +98,7 @@ Re-running this command overwrites the generated files for the "%s" External Cli # success.components-exist -Verify that every component you referenced already exists and is exposed for Lightning Out before deploying. +Verify that every component you referenced already exists and is exposed for Lightning Out 2.0 before deploying. # success.frontdoor diff --git a/src/commands/template/generate/lightning-out/index.ts b/src/commands/template/generate/lightning-out/index.ts index 096010bd..c3af17fe 100644 --- a/src/commands/template/generate/lightning-out/index.ts +++ b/src/commands/template/generate/lightning-out/index.ts @@ -149,8 +149,6 @@ export default class LightningOut extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); - public static readonly state = 'beta'; - public static readonly hidden = true; public static readonly flags = { 'app-name': Flags.string({ summary: messages.getMessage('flags.app-name.summary'), required: false }), diff --git a/test/commands/template/generate/lightning-out/index.test.ts b/test/commands/template/generate/lightning-out/index.test.ts index 8e2d92e2..3fc286ed 100644 --- a/test/commands/template/generate/lightning-out/index.test.ts +++ b/test/commands/template/generate/lightning-out/index.test.ts @@ -42,9 +42,9 @@ describe('template generate lightning-out (unit)', () => { $$.restore(); }); - it('is a beta, hidden command', () => { - expect(LightningOut.state).to.equal('beta'); - expect(LightningOut.hidden).to.equal(true); + it('is a GA command (neither beta nor hidden)', () => { + expect(LightningOut.state).to.equal(undefined); + expect(LightningOut.hidden).to.not.equal(true); }); it('renders the output dir into success.next-step and includes --api-version only when the suffix is supplied', () => { From 9721845ca84d13a9cf40ec37eff39e569a8de835 Mon Sep 17 00:00:00 2001 From: akashdhake Date: Thu, 15 Oct 2026 22:55:57 +0530 Subject: [PATCH 2/3] feat(lightning-out): @W-24501804@ add CLWR site link, org-wide settings and App ID guidance Add post-run guidance for the Lightning Out 2.0 scaffold: - CLWR: link the app to an Experience Cloud site on the Linked Communities Site tab in Lightning Out 2.0 App Manager. - Warn that the generated MyDomain and Security settings are org-wide. - Say where to find the App ID and to set it as the app-id attribute. Move the --runtime detail from the flag summary into its description. --- messages/lightningOut.md | 16 ++++++++++++++-- .../template/generate/lightning-out/index.ts | 3 +++ .../generate/lightning-out/index.test.ts | 13 +++++++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/messages/lightningOut.md b/messages/lightningOut.md index 1aff0c86..0b9ee104 100644 --- a/messages/lightningOut.md +++ b/messages/lightningOut.md @@ -38,7 +38,11 @@ Developer name of the External Client Application associated with the app. # flags.runtime.summary -Runtime the app targets. LWR_CORE serves from your Salesforce org for authenticated users; CLWR serves from an Experience Cloud site (guest access, extra site-deployment step). +Runtime the app targets: LWR_CORE or CLWR. + +# flags.runtime.description + +LWR_CORE serves the app from your Salesforce org to authenticated users. CLWR serves it from an Experience Cloud site to guest and authenticated users. After you deploy a CLWR app, link it to your site in Setup. # flags.host-domains.summary @@ -86,7 +90,7 @@ Scaffold generated in %s. Deploy it with: sf project deploy start --source-dir % # success.app-id -After deploying, note the LightningOutApp's App ID from Setup; your host page needs it to embed the app. +After deploying, copy the App ID from Lightning Out 2.0 App Manager in Setup, and set it as the "app-id" attribute on the tag on your host page. For LWR_CORE, this is what adds your host domains to the allowed frame ancestors. # success.dont-delete @@ -100,6 +104,14 @@ Re-running this command overwrites the generated files for the "%s" External Cli Verify that every component you referenced already exists and is exposed for Lightning Out 2.0 before deploying. +# success.org-settings + +The generated MyDomain and Security settings apply to the whole org when you deploy them: isFirstPartyCookieUseRequired is set to false and enableOauthCorsPolicy is set to true. Review both settings before deploying to a production org. + +# success.clwr-site + +For CLWR, link the app to your Experience Cloud site after deploying. From Setup, in the Quick Find box, enter Lightning Out, and then select Lightning Out 2.0 App Manager. Edit the app, select your site on the "Linked Communities Site" tab, and save. Then follow the steps in the "Complete Deployment in Experience Builder" dialog, which include publishing the site. + # success.frontdoor For CLWR, host pages must complete a frontdoor.jsp handoff before the embedded app can authenticate. diff --git a/src/commands/template/generate/lightning-out/index.ts b/src/commands/template/generate/lightning-out/index.ts index c3af17fe..1c08e05f 100644 --- a/src/commands/template/generate/lightning-out/index.ts +++ b/src/commands/template/generate/lightning-out/index.ts @@ -156,6 +156,7 @@ export default class LightningOut extends SfCommand { runtime: Flags.option({ options: ['LWR_CORE', 'CLWR'] as const, summary: messages.getMessage('flags.runtime.summary'), + description: messages.getMessage('flags.runtime.description'), })(), 'host-domains': Flags.string({ summary: messages.getMessage('flags.host-domains.summary'), multiple: true }), components: Flags.string({ summary: messages.getMessage('flags.components.summary'), multiple: true }), @@ -194,12 +195,14 @@ export default class LightningOut extends SfCommand { const outputDir = opts.outputdir ?? '.'; const apiVersionSuffix = belowFloor ? ' --api-version 68.0' : ''; this.log(messages.getMessage('success.next-step', [outputDir, shellQuoteArg(outputDir), apiVersionSuffix])); + this.warn(messages.getMessage('success.org-settings')); this.info(messages.getMessage('success.app-id')); this.info(messages.getMessage('success.dont-delete')); this.info(messages.getMessage('success.eca-overwrite', [opts.eca.name ?? ''])); this.info(messages.getMessage('success.components-exist')); // frontdoor.jsp handoff is a CLWR-only concern; don't show it for LWR_CORE runs. if (opts.runtime === 'CLWR') { + this.info(messages.getMessage('success.clwr-site')); this.info(messages.getMessage('success.frontdoor')); } diff --git a/test/commands/template/generate/lightning-out/index.test.ts b/test/commands/template/generate/lightning-out/index.test.ts index 3fc286ed..153c1ec8 100644 --- a/test/commands/template/generate/lightning-out/index.test.ts +++ b/test/commands/template/generate/lightning-out/index.test.ts @@ -61,6 +61,19 @@ describe('template generate lightning-out (unit)', () => { expect(atOrAboveFloor).to.not.include('--api-version'); }); + it('describes the CLWR site link and org-wide settings in the output messages', () => { + expect(messages.getMessage('success.clwr-site')).to.include('Linked Communities Site'); + expect(messages.getMessage('success.org-settings')) + .to.include('isFirstPartyCookieUseRequired') + .and.to.include('enableOauthCorsPolicy'); + expect(messages.getMessage('success.app-id')).to.include('app-id').and.to.include('Lightning Out 2.0 App Manager'); + }); + + it('keeps the runtime flag summary short and puts the detail in its description', () => { + expect(LightningOut.flags.runtime.summary).to.not.include('Setup'); + expect(LightningOut.flags.runtime.description).to.include('link it to your site in Setup'); + }); + describe('mergeLightningOutInputs', () => { it('takes appName/eca.name from flags over the definition file', () => { const { opts } = mergeLightningOutInputs( From 06f363a2104dac99612ca1d825491176768fb001 Mon Sep 17 00:00:00 2001 From: akashdhake Date: Thu, 15 Oct 2026 23:04:45 +0530 Subject: [PATCH 3/3] feat(lightning-out): @W-24501804@ address review feedback on post-run messages - Rename success.org-settings to warning.org-settings and print it before the next-step line, since it warns about the deploy that follows. - Print the CLWR site-link guidance before the App ID line. - Reword the app-id sentence to name the CSP frame-ancestors directive. - Replace string-only tests with behavior tests of run() output (CLWR-only guidance, org-wide warning). --- messages/lightningOut.md | 10 +-- .../template/generate/lightning-out/index.ts | 12 ++-- .../generate/lightning-out/index.test.ts | 69 ++++++++++++++++--- 3 files changed, 74 insertions(+), 17 deletions(-) diff --git a/messages/lightningOut.md b/messages/lightningOut.md index 0b9ee104..20083094 100644 --- a/messages/lightningOut.md +++ b/messages/lightningOut.md @@ -84,13 +84,17 @@ Ignoring unrecognized key "%s" in --definition-file. Your local project's sourceApiVersion (%s) is below 68.0, the minimum API version this scaffold supports for deployment. Set sourceApiVersion to 68.0 or later in sfdx-project.json, or pass --api-version 68.0 or later when you deploy. +# warning.org-settings + +The generated MyDomain and Security settings apply to the whole org when you deploy them: isFirstPartyCookieUseRequired is set to false and enableOauthCorsPolicy is set to true. Review both settings before deploying to a production org. + # success.next-step Scaffold generated in %s. Deploy it with: sf project deploy start --source-dir %s%s # success.app-id -After deploying, copy the App ID from Lightning Out 2.0 App Manager in Setup, and set it as the "app-id" attribute on the tag on your host page. For LWR_CORE, this is what adds your host domains to the allowed frame ancestors. +After deploying, copy the App ID from Lightning Out 2.0 App Manager in Setup, and set it as the "app-id" attribute on the tag on your host page. For LWR_CORE apps, the "app-id" attribute is what adds your host domains to the CSP frame-ancestors directive. # success.dont-delete @@ -104,10 +108,6 @@ Re-running this command overwrites the generated files for the "%s" External Cli Verify that every component you referenced already exists and is exposed for Lightning Out 2.0 before deploying. -# success.org-settings - -The generated MyDomain and Security settings apply to the whole org when you deploy them: isFirstPartyCookieUseRequired is set to false and enableOauthCorsPolicy is set to true. Review both settings before deploying to a production org. - # success.clwr-site For CLWR, link the app to your Experience Cloud site after deploying. From Setup, in the Quick Find box, enter Lightning Out, and then select Lightning Out 2.0 App Manager. Edit the app, select your site on the "Linked Communities Site" tab, and save. Then follow the steps in the "Complete Deployment in Experience Builder" dialog, which include publishing the site. diff --git a/src/commands/template/generate/lightning-out/index.ts b/src/commands/template/generate/lightning-out/index.ts index 1c08e05f..2c09b437 100644 --- a/src/commands/template/generate/lightning-out/index.ts +++ b/src/commands/template/generate/lightning-out/index.ts @@ -189,20 +189,24 @@ export default class LightningOut extends SfCommand { this.warn(messages.getMessage('warning.source-api-version', [String(projApi)])); } - // Success guidance (suppressed automatically under --json). + // The org-wide settings notice is a warning, so it also appears in the --json `warnings` array. + this.warn(messages.getMessage('warning.org-settings')); + + // Success guidance (log/info are suppressed automatically under --json). // Only pin --api-version to the 68.0 deploy floor when the project is below it; otherwise omit // the optional flag so the user's own (>= floor) project default applies rather than being downgraded. const outputDir = opts.outputdir ?? '.'; const apiVersionSuffix = belowFloor ? ' --api-version 68.0' : ''; this.log(messages.getMessage('success.next-step', [outputDir, shellQuoteArg(outputDir), apiVersionSuffix])); - this.warn(messages.getMessage('success.org-settings')); + if (opts.runtime === 'CLWR') { + this.info(messages.getMessage('success.clwr-site')); + } this.info(messages.getMessage('success.app-id')); this.info(messages.getMessage('success.dont-delete')); this.info(messages.getMessage('success.eca-overwrite', [opts.eca.name ?? ''])); this.info(messages.getMessage('success.components-exist')); - // frontdoor.jsp handoff is a CLWR-only concern; don't show it for LWR_CORE runs. + // The frontdoor.jsp handoff is a CLWR-only concern; don't show it for LWR_CORE runs. if (opts.runtime === 'CLWR') { - this.info(messages.getMessage('success.clwr-site')); this.info(messages.getMessage('success.frontdoor')); } diff --git a/test/commands/template/generate/lightning-out/index.test.ts b/test/commands/template/generate/lightning-out/index.test.ts index 153c1ec8..b7388659 100644 --- a/test/commands/template/generate/lightning-out/index.test.ts +++ b/test/commands/template/generate/lightning-out/index.test.ts @@ -20,7 +20,8 @@ import * as path from 'node:path'; import { Messages } from '@salesforce/core'; import { TestContext } from '@salesforce/core/testSetup'; import { expect } from 'chai'; -import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import { stubSfCommandUx, stubUx } from '@salesforce/sf-plugins-core'; +import { TemplateService } from '@salesforce/templates'; import LightningOut, { mergeLightningOutInputs, readDefinition, @@ -35,8 +36,9 @@ const messages = Messages.loadMessages('@salesforce/plugin-templates', 'lightnin describe('template generate lightning-out (unit)', () => { const $$ = new TestContext(); + let cmdStubs: ReturnType; beforeEach(() => { - stubSfCommandUx($$.SANDBOX); + cmdStubs = stubSfCommandUx($$.SANDBOX); }); afterEach(() => { $$.restore(); @@ -61,12 +63,63 @@ describe('template generate lightning-out (unit)', () => { expect(atOrAboveFloor).to.not.include('--api-version'); }); - it('describes the CLWR site link and org-wide settings in the output messages', () => { - expect(messages.getMessage('success.clwr-site')).to.include('Linked Communities Site'); - expect(messages.getMessage('success.org-settings')) - .to.include('isFirstPartyCookieUseRequired') - .and.to.include('enableOauthCorsPolicy'); - expect(messages.getMessage('success.app-id')).to.include('app-id').and.to.include('Lightning Out 2.0 App Manager'); + describe('post-run output', () => { + const base = [ + '--app-name', + 'MyLoApp', + '--eca-name', + 'MyLoAppEca', + '--eca-contact-email', + 'dev@example.com', + '--eca-callback-url', + 'https://example.com/cb', + '--host-domains', + 'https://example.com', + ]; + + beforeEach(() => { + stubUx($$.SANDBOX); + $$.SANDBOX.stub(TemplateService.prototype, 'create').resolves({ + outputDir: '.', + created: [], + rawOutput: '', + }); + }); + + it('shows the site-link and frontdoor guidance for CLWR', async () => { + await LightningOut.run([...base, '--runtime', 'CLWR']); + const info = cmdStubs.info.args.flat(); + expect(info).to.include(messages.getMessage('success.clwr-site')); + expect(info).to.include(messages.getMessage('success.frontdoor')); + expect(messages.getMessage('success.clwr-site')).to.include('Linked Communities Site'); + }); + + it('omits the CLWR guidance for LWR_CORE', async () => { + await LightningOut.run([...base, '--runtime', 'LWR_CORE']); + const info = cmdStubs.info.args.flat(); + expect(info).to.not.include(messages.getMessage('success.clwr-site')); + expect(info).to.not.include(messages.getMessage('success.frontdoor')); + expect(info).to.include(messages.getMessage('success.app-id')); + }); + + it('warns that the generated settings are org-wide for every runtime', async () => { + for (const runtime of ['LWR_CORE', 'CLWR']) { + cmdStubs.warn.resetHistory(); + // eslint-disable-next-line no-await-in-loop + await LightningOut.run([...base, '--runtime', runtime]); + const warned = cmdStubs.warn.args.flat(); + expect(warned).to.include(messages.getMessage('warning.org-settings')); + } + expect(messages.getMessage('warning.org-settings')) + .to.include('isFirstPartyCookieUseRequired') + .and.to.include('enableOauthCorsPolicy'); + }); + + it('points to the App ID location and the app-id attribute', () => { + expect(messages.getMessage('success.app-id')) + .to.include('Lightning Out 2.0 App Manager') + .and.to.include('"app-id"'); + }); }); it('keeps the runtime flag summary short and puts the detail in its description', () => {