88import path from 'node:path' ;
99import url from 'node:url' ;
1010import { SfCommand , Flags } from '@salesforce/sf-plugins-core' ;
11- import { Messages , SfProject } from '@salesforce/core' ;
11+ import { Messages , SfProject , Logger } from '@salesforce/core' ;
1212import { cmpDev } from '@lwrjs/api' ;
1313import { ComponentUtils } from '../../../shared/componentUtils.js' ;
1414import { PromptUtils } from '../../../shared/promptUtils.js' ;
15+ import { OrgUtils } from '../../../shared/orgUtils.js' ;
16+ import { PreviewUtils } from '../../../shared/previewUtils.js' ;
1517
1618Messages . importMessagesDirectoryFromMetaUrl ( import . meta. url ) ;
1719const messages = Messages . loadMessages ( '@salesforce/plugin-lightning-dev' , 'lightning.dev.component' ) ;
20+ const appMessages = Messages . loadMessages ( '@salesforce/plugin-lightning-dev' , 'lightning.dev.app' ) ;
21+ const sharedMessages = Messages . loadMessages ( '@salesforce/plugin-lightning-dev' , 'shared.utils' ) ;
1822
1923export default class LightningDevComponent extends SfCommand < void > {
2024 public static readonly summary = messages . getMessage ( 'summary' ) ;
@@ -27,13 +31,36 @@ export default class LightningDevComponent extends SfCommand<void> {
2731 char : 'n' ,
2832 requiredOrDefaulted : false ,
2933 } ) ,
30- // TODO should this be required or optional?
31- // We don't technically need this if your components are simple / don't need any data from your org
32- 'target-org' : Flags . optionalOrg ( ) ,
34+ 'target-org' : Flags . requiredOrg ( ) ,
3335 } ;
3436
3537 public async run ( ) : Promise < void > {
3638 const { flags } = await this . parse ( LightningDevComponent ) ;
39+ const logger = await Logger . child ( this . ctor . name ) ;
40+
41+ // Org connection and setup
42+ const targetOrg = flags [ 'target-org' ] ;
43+ const connection = targetOrg . getConnection ( undefined ) ;
44+ const username = connection . getUsername ( ) ;
45+ if ( ! username ) {
46+ throw new Error ( appMessages . getMessage ( 'error.username' ) ) ;
47+ }
48+
49+ const localDevEnabled = await OrgUtils . isLocalDevEnabled ( connection ) ;
50+ if ( ! localDevEnabled ) {
51+ throw new Error ( sharedMessages . getMessage ( 'error.localdev.not.enabled' ) ) ;
52+ }
53+
54+ OrgUtils . ensureMatchingAPIVersion ( connection ) ;
55+
56+ logger . debug ( 'Configuring local web server identity' ) ;
57+ const appServerIdentity = await PreviewUtils . getOrCreateAppServerIdentity ( connection ) ;
58+ const ldpServerToken = appServerIdentity . identityToken ;
59+ const ldpServerId = appServerIdentity . usernameToServerEntityIdMap [ username ] ;
60+ if ( ! ldpServerId ) {
61+ throw new Error ( appMessages . getMessage ( 'error.identitydata.entityid' ) ) ;
62+ }
63+
3764 const project = await SfProject . resolve ( ) ;
3865
3966 const namespacePaths = await ComponentUtils . getNamespacePaths ( project ) ;
@@ -89,12 +116,15 @@ export default class LightningDevComponent extends SfCommand<void> {
89116
90117 const dirname = path . dirname ( url . fileURLToPath ( import . meta. url ) ) ;
91118 const rootDir = path . resolve ( dirname , '../../../..' ) ;
92- const port = parseInt ( process . env . PORT ?? '3000' , 10 ) ;
119+ const serverPorts = await PreviewUtils . getNextAvailablePorts ( ) ;
120+ logger . debug (
121+ `Next available ports for component preview are http=${ serverPorts . httpPort } , https=${ serverPorts . httpsPort } `
122+ ) ;
93123
94124 await cmpDev ( {
95125 rootDir,
96126 mode : 'dev' ,
97- port,
127+ port : serverPorts . httpPort ,
98128 name : `c/${ name } ` ,
99129 namespacePaths,
100130 } ) ;
0 commit comments