UNPKG

@salesforce/plugin-org

Version:

Commands to interact with Salesforce orgs

150 lines 7.87 kB
/* * Copyright 2026, Salesforce, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { Flags, SfCommand, requiredOrgFlagWithDeprecations, loglevel, orgApiVersionFlagWithDeprecations, } from '@salesforce/sf-plugins-core'; import { AuthInfo, envVars, Messages, SfError, trimTo15 } from '@salesforce/core'; import { camelCaseToTitleCase } from '@salesforce/kit'; import { getAliasByUsername } from '../../shared/utils.js'; import { getStyledValue } from '../../shared/orgHighlighter.js'; import { OrgListUtil } from '../../shared/orgListUtil.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-org', 'display'); const sharedMessages = Messages.loadMessages('@salesforce/plugin-org', 'messages'); const secretsMessages = Messages.loadMessages('@salesforce/plugin-org', 'secrets-redacted'); export class OrgDisplayCommand extends SfCommand { static summary = messages.getMessage('summary'); static description = messages.getMessage('description'); static examples = messages.getMessages('examples'); static aliases = ['force:org:display']; static deprecateAliases = true; static flags = { 'target-org': requiredOrgFlagWithDeprecations, 'api-version': orgApiVersionFlagWithDeprecations, verbose: Flags.boolean({ summary: messages.getMessage('flags.verbose.summary'), }), loglevel, }; org; async run() { const { flags } = await this.parse(OrgDisplayCommand); this.org = flags['target-org']; this.org.getConnection(flags['api-version']); try { // TODO: Once env var is removed, this refresh could be removed. // the auth file might have a stale access token. We want to refresh it before getting the fields await this.org.refreshAuth(); } catch (error) { // even if this fails, we want to display the information we can read from the auth file this.warn('unable to refresh auth for org'); } const accessTokenRedactedMessage = secretsMessages.getMessage('redacted.accessToken'); const sfdxAuthUrlRedactedMessage = secretsMessages.getMessage('redacted.sfdxAuthUrl'); const passwordRedactedMessage = secretsMessages.getMessage('redacted.userPassword'); const envVarAsATempWorkaroundMessage = secretsMessages.getMessage('temp.envVarWorkaround', ['sf org display']); const showSecretsEnvVarIsSet = envVars.getBoolean('SF_TEMP_SHOW_SECRETS', false); const envVarIsSetWarning = secretsMessages.getMessage('temp.envVarIsSet', ['sf org display']); // translate to alias if necessary const authInfo = await AuthInfo.create({ username: this.org.getUsername() }); const fields = authInfo.getFields(true); const isScratchOrg = Boolean(fields.devHubUsername); const scratchOrgInfo = isScratchOrg && fields.orgId ? await this.getScratchOrgInformation(fields) : {}; const getSfdxAuthUrlOutput = () => { if (flags.verbose && fields.refreshToken) { // TODO: Remove env var workaround return showSecretsEnvVarIsSet ? authInfo.getSfdxAuthUrl() : sfdxAuthUrlRedactedMessage; } return undefined; }; const returnValue = { // renamed properties id: fields.orgId, devHubId: fields.devHubUsername, // copied properties apiVersion: fields.instanceApiVersion, // Access token will always exist, don't check for value first // TODO: Remove env var workaround accessToken: showSecretsEnvVarIsSet ? fields.accessToken : accessTokenRedactedMessage, instanceUrl: fields.instanceUrl, username: fields.username, clientId: fields.clientId, // Password only exists if it was generated locally, check for value first // TODO: Remove env var workaround password: fields.password ? (showSecretsEnvVarIsSet ? fields.password : passwordRedactedMessage) : undefined, ...scratchOrgInfo, // properties with more complex logic connectedStatus: isScratchOrg ? undefined : await OrgListUtil.determineConnectedStatusForNonScratchOrg(fields.username), sfdxAuthUrl: getSfdxAuthUrlOutput(), alias: await getAliasByUsername(fields.username), // TODO: deprecate these values clientApps: fields.clientApps ? Object.keys(fields.clientApps).join(',') : undefined, }; if (showSecretsEnvVarIsSet) { this.warn(envVarIsSetWarning); this.warn(sharedMessages.getMessage('SecurityWarning')); } else { this.warn(envVarAsATempWorkaroundMessage); } this.print(returnValue); return returnValue; } print(result) { this.log(); const tableRows = Object.entries(result) .filter(([, value]) => value !== undefined && value !== null) // some values won't exist .sort() // this command always alphabetizes the table rows .map(([key, value]) => ({ key: camelCaseToTitleCase(key), value: typeof value === 'string' ? getStyledValue(key, value) : value, })); this.table({ overflow: 'wrap', data: tableRows, columns: [ { key: 'key', name: 'KEY' }, { key: 'value', name: 'VALUE' }, ], title: 'Org Description', }); } async getScratchOrgInformation(fields) { const hubOrg = await this.org.getDevHubOrg(); // we know this is a scratch org so it must have a hubOrg and that'll have a username const hubUsername = hubOrg?.getUsername(); // This query can return multiple records that match the 15 char ID because `ScratchOrgInfo.ScratchOrg` isn't a case-sensitive field // so we look for the record that matches the scratch org username in the auth file. // If that doesn't match (e.g., when calling `org display` with a username that is not the scratch org admin), use the instance URL const result = (await OrgListUtil.retrieveScratchOrgInfoFromDevHub(hubUsername, [trimTo15(fields.orgId)])).find((rec) => rec.SignupUsername === fields.username || rec.LoginUrl === fields.instanceUrl); if (result) { return { status: result.Status, devHubId: hubUsername, expirationDate: result.ExpirationDate, createdBy: result.CreatedBy?.Username, edition: result.Edition ?? undefined, // null for snapshot orgs, possibly others. Marking it undefined keeps it out of json output namespace: result.Namespace ?? undefined, // may be null on server orgName: result.OrgName, createdDate: result.CreatedDate, signupUsername: result.SignupUsername, }; } throw new SfError(messages.getMessage('noScratchOrgInfoError', [trimTo15(fields.orgId), hubUsername]), 'NoScratchInfo', [messages.getMessage('noScratchOrgInfoAction')]); } } //# sourceMappingURL=display.js.map