From 113d56ac5cecb68f5adf89bd90c06281800943c6 Mon Sep 17 00:00:00 2001 From: Shane McLaughlin Date: Wed, 10 Jan 2024 13:50:26 -0600 Subject: [PATCH] feat: use new inquirer (#902) * feat: use new inquirer * fix: use new sf-plugins-core prompts * refactor: real plugins-core, use built-in confirm prompt * chore: bump deps --- command-snapshot.json | 12 +- messages/messages.md | 4 - package.json | 14 +- src/authBaseCommand.ts | 54 --- src/commands/org/list/auth.ts | 10 +- src/commands/org/login/access-token.ts | 24 +- src/commands/org/login/device.ts | 19 +- src/commands/org/login/jwt.ts | 14 +- src/commands/org/login/sfdx-url.ts | 10 +- src/commands/org/login/web.ts | 47 +-- src/commands/org/logout.ts | 245 +++++------- src/common.ts | 59 +-- test/commands/org/login/access-token.test.ts | 154 ++++---- test/commands/org/login/login.device.test.ts | 25 +- test/commands/org/login/login.jwt.test.ts | 38 +- .../commands/org/login/login.sfdx-url.test.ts | 30 +- test/commands/org/login/login.web.test.ts | 19 +- test/commands/org/logout.test.ts | 2 + test/common.test.ts | 40 +- tsconfig.json | 3 +- yarn.lock | 352 +++++++++++------- 21 files changed, 516 insertions(+), 659 deletions(-) delete mode 100644 src/authBaseCommand.ts diff --git a/command-snapshot.json b/command-snapshot.json index 111593d8..a059d81b 100644 --- a/command-snapshot.json +++ b/command-snapshot.json @@ -25,16 +25,7 @@ { "command": "org:login:device", "plugin": "@salesforce/plugin-auth", - "flags": [ - "alias", - "client-id", - "disable-masking", - "instance-url", - "json", - "loglevel", - "set-default", - "set-default-dev-hub" - ], + "flags": ["alias", "client-id", "instance-url", "json", "loglevel", "set-default", "set-default-dev-hub"], "alias": ["force:auth:device:login", "auth:device:login"], "flagChars": ["a", "d", "i", "r", "s"], "flagAliases": [ @@ -111,7 +102,6 @@ "alias", "browser", "client-id", - "disable-masking", "instance-url", "json", "loglevel", diff --git a/messages/messages.md b/messages/messages.md index 88d85fed..ea3222c8 100644 --- a/messages/messages.md +++ b/messages/messages.md @@ -40,10 +40,6 @@ Do you want to authorize this org for use with the Salesforce CLI? Don't prompt for confirmation. -# flags.disable-masking.summary - -Disable masking of user input; use with problematic terminals. - # clientSecretStdin OAuth client secret of personal connected app? Press Enter if it's not required. diff --git a/package.json b/package.json index 38aa1979..8a18b5c0 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,12 @@ "author": "Salesforce", "bugs": "https://github.com/forcedotcom/cli/issues", "dependencies": { - "@oclif/core": "^3.16.0", - "@salesforce/core": "^6.4.4", + "@inquirer/checkbox": "^1.5.0", + "@inquirer/select": "^1.3.1", + "@oclif/core": "^3.18.0", + "@salesforce/core": "^6.4.6", "@salesforce/kit": "^3.0.15", - "@salesforce/sf-plugins-core": "^5.0.13", + "@salesforce/sf-plugins-core": "^7.1.1", "@salesforce/ts-types": "^2.0.9", "chalk": "^5.3.0", "open": "^9.1.0" @@ -17,10 +19,10 @@ "@oclif/plugin-command-snapshot": "^5.0.5", "@salesforce/cli-plugins-testkit": "^5.1.3", "@salesforce/dev-scripts": "^8.2.0", - "@salesforce/plugin-command-reference": "^3.0.59", + "@salesforce/plugin-command-reference": "^3.0.61", "@salesforce/ts-sinon": "^1.4.19", - "eslint-plugin-sf-plugin": "^1.17.0", - "oclif": "^4.1.0", + "eslint-plugin-sf-plugin": "^1.17.1", + "oclif": "^4.2.0", "shx": "0.3.4", "ts-node": "^10.9.2", "typescript": "^5.3.3" diff --git a/src/authBaseCommand.ts b/src/authBaseCommand.ts deleted file mode 100644 index e79d51b2..00000000 --- a/src/authBaseCommand.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2020, salesforce.com, inc. - * All rights reserved. - * Licensed under the BSD 3-Clause license. - * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause - */ - - -import { Messages, Global, Mode } from '@salesforce/core'; -import chalk from 'chalk'; -import { SfCommand } from '@salesforce/sf-plugins-core'; -import { Config } from '@oclif/core'; - -Messages.importMessagesDirectoryFromMetaUrl(import.meta.url) -const messages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); - -function dimMessage(message: string): string { - return chalk.dim(message); -} - -export abstract class AuthBaseCommand extends SfCommand { - public constructor(argv: string[], config: Config) { - super(argv, config); - } - - protected async askForHiddenResponse(messageKey: string, disableMasking = false): Promise { - const msg = dimMessage(messages.getMessage(messageKey)); - const hidden: { response: string } = await this.prompt({ - message: msg, - type: 'input', - name: 'response', - transformer: (input: string) => (disableMasking ? input : '*'.repeat(input.length)), - }); - return hidden.response; - } - - protected async shouldExitCommand(noPrompt?: boolean, message?: string): Promise { - if (Boolean(noPrompt) || Global.getEnvironmentMode() !== Mode.DEMO) { - return false; - } else { - const msg = dimMessage(message ?? messages.getMessage('warnAuth', [this.config.bin])); - const answer = await this.confirm(msg); - return !answer; - } - } - - protected async askForClientSecret(disableMasking = false): Promise { - return this.askForHiddenResponse('clientSecretStdin', disableMasking); - } - - protected async askForAccessToken(disableMasking = false): Promise { - return this.askForHiddenResponse('accessTokenStdin', disableMasking); - } -} diff --git a/src/commands/org/list/auth.ts b/src/commands/org/list/auth.ts index dd3208fe..ba6ae3e2 100644 --- a/src/commands/org/list/auth.ts +++ b/src/commands/org/list/auth.ts @@ -5,13 +5,11 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ - - import { loglevel, SfCommand } from '@salesforce/sf-plugins-core'; import { AuthInfo, Messages, OrgAuthorization } from '@salesforce/core'; type AuthListResult = Omit & { alias: string }; export type AuthListResults = AuthListResult[]; -Messages.importMessagesDirectoryFromMetaUrl(import.meta.url) +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'list'); export default class ListAuth extends SfCommand { @@ -40,16 +38,14 @@ export default class ListAuth extends SfCommand { }); const hasErrors = auths.filter((auth) => !!auth.error).length > 0; - let columns = { + const columns = { alias: { header: 'ALIAS' }, username: { header: 'USERNAME' }, orgId: { header: 'ORG ID' }, instanceUrl: { header: 'INSTANCE URL' }, oauthMethod: { header: 'AUTH METHOD' }, + ...(hasErrors ? { error: { header: 'ERROR' } } : {}), }; - if (hasErrors) { - columns = { ...columns, ...{ error: { header: 'ERROR' } } }; - } this.styledHeader('authenticated orgs'); this.table(mappedAuths, columns); return mappedAuths; diff --git a/src/commands/org/login/access-token.ts b/src/commands/org/login/access-token.ts index c952e7ae..b291cb72 100644 --- a/src/commands/org/login/access-token.ts +++ b/src/commands/org/login/access-token.ts @@ -5,26 +5,23 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ - - -import { Flags, loglevel } from '@salesforce/sf-plugins-core'; +import { Flags, loglevel, SfCommand } from '@salesforce/sf-plugins-core'; import { AuthFields, AuthInfo, Messages, matchesAccessToken, SfError, StateAggregator } from '@salesforce/core'; import { env } from '@salesforce/kit'; -import { Interfaces } from '@oclif/core'; -import { AuthBaseCommand } from '../../../authBaseCommand.js'; +import { InferredFlags } from '@oclif/core/lib/interfaces'; -Messages.importMessagesDirectoryFromMetaUrl(import.meta.url) +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'accesstoken.store'); const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); const ACCESS_TOKEN_FORMAT = '"!"'; -export default class LoginAccessToken extends AuthBaseCommand { +export default class LoginAccessToken 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 deprecateAliases = true; - public static aliases = ['force:auth:accesstoken:store', 'auth:accesstoken:store']; + public static readonly aliases = ['force:auth:accesstoken:store', 'auth:accesstoken:store']; public static readonly flags = { 'instance-url': Flags.url({ @@ -66,7 +63,7 @@ export default class LoginAccessToken extends AuthBaseCommand { loglevel, }; - private flags!: Interfaces.InferredFlags; + private flags!: InferredFlags; public async run(): Promise { const { flags } = await this.parse(LoginAccessToken); @@ -109,7 +106,7 @@ export default class LoginAccessToken extends AuthBaseCommand { if (!this.flags['no-prompt']) { const stateAggregator = await StateAggregator.getInstance(); if (await stateAggregator.orgs.exists(username)) { - return this.confirm(messages.getMessage('overwriteAccessTokenAuthUserFile', [username])); + return this.confirm({ message: messages.getMessage('overwriteAccessTokenAuthUserFile', [username]) }); } } return true; @@ -117,8 +114,11 @@ export default class LoginAccessToken extends AuthBaseCommand { private async getAccessToken(): Promise { const accessToken = - env.getString('SF_ACCESS_TOKEN') ?? env.getString('SFDX_ACCESS_TOKEN') ?? (await this.askForAccessToken()); - + env.getString('SF_ACCESS_TOKEN') ?? + env.getString('SFDX_ACCESS_TOKEN') ?? + (this.flags['no-prompt'] === true + ? '' // will throw when validating + : await this.secretPrompt({ message: commonMessages.getMessage('accessTokenStdin') })); if (!matchesAccessToken(accessToken)) { throw new SfError(messages.getMessage('invalidAccessTokenFormat', [ACCESS_TOKEN_FORMAT])); } diff --git a/src/commands/org/login/device.ts b/src/commands/org/login/device.ts index 048b8d2c..4f371ca0 100644 --- a/src/commands/org/login/device.ts +++ b/src/commands/org/login/device.ts @@ -6,11 +6,10 @@ */ import { AuthFields, AuthInfo, DeviceOauthService, Messages, OAuth2Config } from '@salesforce/core'; -import { Flags, loglevel } from '@salesforce/sf-plugins-core'; +import { Flags, SfCommand, loglevel } from '@salesforce/sf-plugins-core'; import { DeviceCodeResponse } from '@salesforce/core/lib/deviceOauthService.js'; import { ux } from '@oclif/core'; -import { AuthBaseCommand } from '../../../authBaseCommand.js'; -import { Common } from '../../../common.js'; +import common from '../../../common.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'device.login'); @@ -18,11 +17,11 @@ const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'message export type DeviceLoginResult = (AuthFields & DeviceCodeResponse) | Record; -export default class LoginDevice extends AuthBaseCommand { +export default class LoginDevice 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 aliases = ['force:auth:device:login', 'auth:device:login']; + public static readonly aliases = ['force:auth:device:login', 'auth:device:login']; public static readonly deprecateAliases = true; public static readonly flags = { @@ -57,21 +56,15 @@ export default class LoginDevice extends AuthBaseCommand { deprecateAliases: true, aliases: ['setalias'], }), - 'disable-masking': Flags.boolean({ - summary: commonMessages.getMessage('flags.disable-masking.summary'), - hidden: true, - deprecateAliases: true, - aliases: ['disablemasking'], - }), loglevel, }; public async run(): Promise { const { flags } = await this.parse(LoginDevice); - if (await this.shouldExitCommand(false)) return {}; + if (await common.shouldExitCommand(false)) return {}; const oauthConfig: OAuth2Config = { - loginUrl: await Common.resolveLoginUrl(flags['instance-url']?.href), + loginUrl: await common.resolveLoginUrl(flags['instance-url']?.href), clientId: flags['client-id'], }; diff --git a/src/commands/org/login/jwt.ts b/src/commands/org/login/jwt.ts index 229870a1..c1310121 100644 --- a/src/commands/org/login/jwt.ts +++ b/src/commands/org/login/jwt.ts @@ -5,25 +5,25 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { Flags, loglevel } from '@salesforce/sf-plugins-core'; +import { Flags, SfCommand, loglevel } from '@salesforce/sf-plugins-core'; import { AuthFields, AuthInfo, AuthRemover, Logger, Messages, SfError } from '@salesforce/core'; import { Interfaces } from '@oclif/core'; -import { AuthBaseCommand } from '../../../authBaseCommand.js'; -import { Common } from '../../../common.js'; +import common from '../../../common.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'jwt.grant'); const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); -export default class LoginJwt extends AuthBaseCommand { +export default class LoginJwt 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 aliases = ['force:auth:jwt:grant', 'auth:jwt:grant']; + public static readonly aliases = ['force:auth:jwt:grant', 'auth:jwt:grant']; public static readonly deprecateAliases = true; public static readonly flags = { username: Flags.string({ + // eslint-disable-next-line sf-plugin/dash-o char: 'o', summary: messages.getMessage('flags.username.summary'), required: true, @@ -87,7 +87,7 @@ export default class LoginJwt extends AuthBaseCommand { this.flags = flags; let result: AuthFields = {}; - if (await this.shouldExitCommand(flags['no-prompt'])) return {}; + if (await common.shouldExitCommand(flags['no-prompt'])) return {}; try { const authInfo = await this.initAuthInfo(); @@ -116,7 +116,7 @@ export default class LoginJwt extends AuthBaseCommand { privateKeyFile: this.flags['jwt-key-file'], }; - const loginUrl = await Common.resolveLoginUrl(this.flags['instance-url']?.href); + const loginUrl = await common.resolveLoginUrl(this.flags['instance-url']?.href); const oauth2Options = loginUrl ? Object.assign(oauth2OptionsBase, { loginUrl }) : oauth2OptionsBase; diff --git a/src/commands/org/login/sfdx-url.ts b/src/commands/org/login/sfdx-url.ts index 3750bc76..782cd71a 100644 --- a/src/commands/org/login/sfdx-url.ts +++ b/src/commands/org/login/sfdx-url.ts @@ -6,11 +6,11 @@ */ import fs from 'node:fs/promises'; -import { Flags, loglevel } from '@salesforce/sf-plugins-core'; +import { Flags, SfCommand, loglevel } from '@salesforce/sf-plugins-core'; import { AuthFields, AuthInfo, Messages } from '@salesforce/core'; import { AnyJson } from '@salesforce/ts-types'; import { parseJson } from '@salesforce/kit'; -import { AuthBaseCommand } from '../../../authBaseCommand.js'; +import common from '../../../common.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'sfdxurl.store'); @@ -22,11 +22,11 @@ type AuthJson = AnyJson & { result?: AnyJson & { sfdxAuthUrl: string }; sfdxAuthUrl: string; }; -export default class LoginSfdxUrl extends AuthBaseCommand { +export default class LoginSfdxUrl extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description', [AUTH_URL_FORMAT]); public static readonly examples = messages.getMessages('examples'); - public static aliases = ['force:auth:sfdxurl:store', 'auth:sfdxurl:store']; + public static readonly aliases = ['force:auth:sfdxurl:store', 'auth:sfdxurl:store']; public static readonly deprecateAliases = true; public static readonly flags = { @@ -78,7 +78,7 @@ export default class LoginSfdxUrl extends AuthBaseCommand { public async run(): Promise { const { flags } = await this.parse(LoginSfdxUrl); - if (await this.shouldExitCommand(flags['no-prompt'])) return {}; + if (await common.shouldExitCommand(flags['no-prompt'])) return {}; const authFile = flags['sfdx-url-file']; const authStdin = flags['sfdx-url-stdin']; diff --git a/src/commands/org/login/web.ts b/src/commands/org/login/web.ts index 17d4f272..0a0b203a 100644 --- a/src/commands/org/login/web.ts +++ b/src/commands/org/login/web.ts @@ -6,18 +6,16 @@ */ import open, { apps, AppName } from 'open'; -import { Flags, loglevel } from '@salesforce/sf-plugins-core'; +import { Flags, SfCommand, loglevel } from '@salesforce/sf-plugins-core'; import { AuthFields, AuthInfo, Logger, Messages, OAuth2Config, SfError, WebOAuthServer } from '@salesforce/core'; import { Env } from '@salesforce/kit'; -import { Interfaces } from '@oclif/core'; -import { AuthBaseCommand } from '../../../authBaseCommand.js'; -import { Common } from '../../../common.js'; +import common from '../../../common.js'; Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'web.login'); const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); -export default class LoginWeb extends AuthBaseCommand { +export default class LoginWeb extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); @@ -25,12 +23,12 @@ export default class LoginWeb extends AuthBaseCommand { public static readonly aliases = ['force:auth:web:login', 'auth:web:login']; public static readonly flags = { - browser: Flags.string({ + browser: Flags.option({ char: 'b', summary: messages.getMessage('flags.browser.summary'), description: messages.getMessage('flags.browser.description'), options: ['chrome', 'edge', 'firefox'], // These are ones supported by "open" package - }), + })(), 'client-id': Flags.string({ char: 'i', summary: commonMessages.getMessage('flags.client-id.summary'), @@ -62,12 +60,6 @@ export default class LoginWeb extends AuthBaseCommand { deprecateAliases: true, aliases: ['setalias'], }), - 'disable-masking': Flags.boolean({ - summary: commonMessages.getMessage('flags.disable-masking.summary'), - hidden: true, - deprecateAliases: true, - aliases: ['disablemasking'], - }), 'no-prompt': Flags.boolean({ char: 'p', summary: commonMessages.getMessage('flags.no-prompt.summary'), @@ -79,28 +71,24 @@ export default class LoginWeb extends AuthBaseCommand { loglevel, }; - private flags!: Interfaces.InferredFlags; - public async run(): Promise { const { flags } = await this.parse(LoginWeb); - this.flags = flags; if (isSFDXContainerMode()) { throw new SfError(messages.getMessage('deviceWarning'), 'DEVICE_WARNING'); } - if (await this.shouldExitCommand(flags['no-prompt'])) return {}; + if (await common.shouldExitCommand(flags['no-prompt'])) return {}; const oauthConfig: OAuth2Config = { - loginUrl: await Common.resolveLoginUrl(flags['instance-url']?.href), + loginUrl: await common.resolveLoginUrl(flags['instance-url']?.href), clientId: flags['client-id'], + ...(flags['client-id'] + ? { clientSecret: await this.secretPrompt({ message: commonMessages.getMessage('clientSecretStdin') }) } + : {}), }; - if (flags['client-id']) { - oauthConfig.clientSecret = await this.askForClientSecret(flags['disable-masking']); - } - try { - const authInfo = await this.executeLoginFlow(oauthConfig); + const authInfo = await this.executeLoginFlow(oauthConfig, flags.browser); await authInfo.handleAliasAndDefaultSettings({ alias: flags.alias, setDefault: flags['set-default'], @@ -113,21 +101,20 @@ export default class LoginWeb extends AuthBaseCommand { this.logSuccess(successMsg); return fields; } catch (err) { - const error = err as Error; - Logger.childFromRoot('LoginWebCommand').debug(error); - if (error.name === 'AuthCodeExchangeError') { - throw new SfError(messages.getMessage('invalidClientId', [error.message]), undefined, undefined, error); + Logger.childFromRoot('LoginWebCommand').debug(err); + if (err instanceof Error && err.name === 'AuthCodeExchangeError') { + throw new SfError(messages.getMessage('invalidClientId', [err.message]), undefined, undefined, err); } - throw error; + throw err; } } // leave it because it's stubbed in the test // eslint-disable-next-line class-methods-use-this - private async executeLoginFlow(oauthConfig: OAuth2Config): Promise { + private async executeLoginFlow(oauthConfig: OAuth2Config, browser?: string): Promise { const oauthServer = await WebOAuthServer.create({ oauthConfig }); await oauthServer.start(); - const app = this.flags.browser && this.flags.browser in apps ? (this.flags.browser as AppName) : undefined; + const app = browser && browser in apps ? (browser as AppName) : undefined; const openOptions = app ? { app: { name: apps[app] }, wait: false } : { wait: false }; await open(oauthServer.getAuthorizationUrl(), openOptions); return oauthServer.authorizeAndSave(); diff --git a/src/commands/org/logout.ts b/src/commands/org/logout.ts index f13e92df..69353d82 100644 --- a/src/commands/org/logout.ts +++ b/src/commands/org/logout.ts @@ -5,8 +5,6 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ - - import os from 'node:os'; import { AuthInfo, @@ -18,25 +16,24 @@ import { OrgAuthorization, OrgConfigProperties, } from '@salesforce/core'; -import { Flags, loglevel, Separator } from '@salesforce/sf-plugins-core'; -import { Interfaces } from '@oclif/core'; +import checkbox, { Separator } from '@inquirer/checkbox'; +import { Flags, loglevel, SfCommand } from '@salesforce/sf-plugins-core'; import chalk from 'chalk'; -import { AuthBaseCommand } from '../../authBaseCommand.js'; -Messages.importMessagesDirectoryFromMetaUrl(import.meta.url) +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'logout'); const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); type Choice = { name: string; value: OrgAuthorization }; export type AuthLogoutResults = string[]; -export default class Logout extends AuthBaseCommand { +export default class Logout 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 deprecateAliases = true; - public static aliases = ['force:auth:logout', 'auth:logout']; + public static readonly aliases = ['force:auth:logout', 'auth:logout']; public static readonly flags = { 'target-org': Flags.string({ @@ -63,65 +60,11 @@ export default class Logout extends AuthBaseCommand { loglevel, }; - private flags!: Interfaces.InferredFlags; - - private static buildChoices(orgAuths: OrgAuthorization[], all: boolean): Array { - const maxUsernameLength = Math.max('Username'.length, ...orgAuths.map((orgAuth) => orgAuth.username.length)); - const maxAliasLength = Math.max( - 'Aliases'.length, - ...orgAuths.map((orgAuth) => (orgAuth.aliases ? orgAuth.aliases.join(',') : '').length) - ); - const maxConfigLength = Math.max( - 'Configs'.length, - ...orgAuths.map((orgAuth) => (orgAuth.configs ? orgAuth.configs.join(',') : '').length) - ); - const maxTypeLength = Math.max( - 'Type'.length, - ...orgAuths.map((orgAuth) => { - if (orgAuth.isScratchOrg) { - return 'Scratch'.length; - } - if (orgAuth.isDevHub) { - return 'DevHub'.length; - } - if (orgAuth.isSandbox) { - return 'Sandbox'.length; - } - return 0; - }) - ); - const choices = orgAuths - .map((orgAuth) => { - const aliasString = (orgAuth.aliases ? orgAuth.aliases.join(',') : '').padEnd(maxAliasLength, ' '); - const configString = (orgAuth.configs ? orgAuth.configs.join(',') : '').padEnd(maxConfigLength, ' '); - const typeString = chalk.dim( - (orgAuth.isScratchOrg ? 'Scratch' : orgAuth.isDevHub ? 'DevHub' : orgAuth.isSandbox ? 'Sandbox' : '').padEnd( - maxTypeLength, - ' ' - ) - ); - // username - aliases - configs - const key = `${chalk.bold( - orgAuth.username.padEnd(maxUsernameLength) - )} | ${typeString} | ${aliasString} | ${chalk.yellowBright(configString)}`; - return { name: key, value: orgAuth, checked: all, short: `${os.EOL}${orgAuth.username}` }; - }) - .sort((a, b) => a.value.username.localeCompare(b.value.username)); - const userHeader = `${'Username'.padEnd(maxUsernameLength, ' ')}`; - const aliasHeader = `${'Aliases'.padEnd(maxAliasLength, ' ')}`; - const configHeader = `${'Configs'.padEnd(maxConfigLength, ' ')}`; - const typeHeader = `${'Type'.padEnd(maxTypeLength, ' ')}`; - return [new Separator(` ${userHeader} | ${typeHeader} | ${aliasHeader} | ${configHeader}`), ...choices]; - } - public async run(): Promise { const { flags } = await this.parse(Logout); - this.flags = flags; - this.configAggregator = await ConfigAggregator.create(); - const remover = await AuthRemover.create(); - let orgAuths: OrgAuthorization[] = []; const targetUsername = - this.flags['target-org'] ?? (this.configAggregator.getInfo(OrgConfigProperties.TARGET_ORG).value as string); + flags['target-org'] ?? + ((await ConfigAggregator.create()).getInfo(OrgConfigProperties.TARGET_ORG).value as string); // if no-prompt, there must be a resolved target-org or --all if (flags['no-prompt'] && !targetUsername && !flags.all) { @@ -131,37 +74,38 @@ export default class Logout extends AuthBaseCommand { if (this.jsonEnabled() && !targetUsername && !flags.all) { throw messages.createError('noOrgSpecifiedWithJson'); } - - if (this.shouldFindAllAuths(targetUsername)) { - orgAuths = await AuthInfo.listAllAuthorizations(); - } else if (targetUsername) { - orgAuths = await AuthInfo.listAllAuthorizations( - (orgAuth) => orgAuth.username === targetUsername || !!orgAuth.aliases?.includes(targetUsername) - ); - } else { - // just for clarity - orgAuths = []; - } + const shouldFindAllAuths = + targetUsername && !flags.all + ? false + : flags.all || Global.getEnvironmentMode() === Mode.DEMO || !flags['no-prompt']; + + const orgAuths = shouldFindAllAuths + ? await AuthInfo.listAllAuthorizations() + : targetUsername + ? (await AuthInfo.listAllAuthorizations()).filter( + (orgAuth) => orgAuth.username === targetUsername || !!orgAuth.aliases?.includes(targetUsername) + ) + : []; if (orgAuths.length === 0) { - if (this.flags['target-org']) { + if (flags['target-org']) { // user specified a target org but it was not resolved, issue success message and return - this.logSuccess(messages.getMessage('logoutOrgCommandSuccess', [this.flags['target-org']])); - return [this.flags['target-org']]; + this.logSuccess(messages.getMessage('logoutOrgCommandSuccess', [flags['target-org']])); + return [flags['target-org']]; } this.info(messages.getMessage('noOrgsFound')); return []; } + const skipPrompt = flags['no-prompt'] || this.jsonEnabled(); - const { orgs, confirmed } = await this.promptForOrgsToRemove(orgAuths, flags.all); + const selectedOrgs = this.maybeWarnScratchOrgs( + skipPrompt ? orgAuths : await promptForOrgsToRemove(orgAuths, flags.all) + ); - if (confirmed) { - for (const org of orgs) { - // run sequentially to avoid configFile concurrency issues - // eslint-disable-next-line no-await-in-loop - await remover.removeAuth(org.username); - } - const loggedOutUsernames = orgs.map((org) => org.username); + if (skipPrompt || (await this.confirm({ message: getOrgConfirmationMessage(selectedOrgs, orgAuths.length) }))) { + const remover = await AuthRemover.create(); + const loggedOutUsernames = selectedOrgs.map((org) => org.username); + await Promise.all(loggedOutUsernames.map((username) => remover.removeAuth(username))); this.logSuccess(messages.getMessage('logoutOrgCommandSuccess', [loggedOutUsernames.join(os.EOL)])); return loggedOutUsernames; } else { @@ -170,68 +114,77 @@ export default class Logout extends AuthBaseCommand { } } - private shouldFindAllAuths(targetUsername: string | undefined): boolean { - if (targetUsername && !this.flags.all) { - return false; + /** Warning about logging out of a scratch org and losing access to it */ + private maybeWarnScratchOrgs(orgs: OrgAuthorization[]): OrgAuthorization[] { + if (orgs.some((org) => org.isScratchOrg)) { + this.warn(messages.getMessage('warning')); } - return this.flags.all || Global.getEnvironmentMode() === Mode.DEMO || !this.flags['no-prompt']; + return orgs; } +} - private async promptForOrgsToRemove( - orgAuths: OrgAuthorization[], - all: boolean - ): Promise<{ orgs: OrgAuthorization[]; confirmed: boolean }> { - if (this.flags['no-prompt'] || this.jsonEnabled()) { - return { orgs: orgAuths, confirmed: true }; - } - - if (orgAuths.length === 1) { - if (orgAuths[0].isScratchOrg) { - this.warn(messages.getMessage('warning')); +const promptForOrgsToRemove = async (orgAuths: OrgAuthorization[], all: boolean): Promise => + orgAuths.length === 1 + ? orgAuths + : checkbox({ + message: messages.getMessage('prompt.select-envs'), + // pick the orgs to delete - if flags.all - set each org to selected + // otherwise prompt the user to select the orgs to delete + choices: buildChoices(orgAuths, all), + loop: true, + }); + +const getOrgConfirmationMessage = (selectedOrgs: OrgAuthorization[], originalOrgCount: number): string => + selectedOrgs.length === originalOrgCount + ? messages.getMessage('prompt.confirm-all') + : messages.getMessage('prompt.confirm', [selectedOrgs.length, selectedOrgs.length > 1 ? 's' : '']); + +/** A whole bunch of custom formatting to make the list look nicer */ +const buildChoices = (orgAuths: OrgAuthorization[], all: boolean): Array => { + const maxUsernameLength = Math.max('Username'.length, ...orgAuths.map((orgAuth) => orgAuth.username.length)); + const maxAliasLength = Math.max( + 'Aliases'.length, + ...orgAuths.map((orgAuth) => (orgAuth.aliases ? orgAuth.aliases.join(',') : '').length) + ); + const maxConfigLength = Math.max( + 'Configs'.length, + ...orgAuths.map((orgAuth) => (orgAuth.configs ? orgAuth.configs.join(',') : '').length) + ); + const maxTypeLength = Math.max( + 'Type'.length, + ...orgAuths.map((orgAuth) => { + if (orgAuth.isScratchOrg) { + return 'Scratch'.length; } - if (await this.confirm(messages.getMessage('prompt.confirm.single', [orgAuths[0].username]), 30_000, false)) { - return { orgs: orgAuths, confirmed: true }; - } else { - return { orgs: [], confirmed: false }; + if (orgAuth.isDevHub) { + return 'DevHub'.length; } - } - - // pick the orgs to delete - if this.flags.all - set each org to selected - // otherwise prompt the user to select the orgs to delete - const choices = Logout.buildChoices(orgAuths, all); - const { orgs, confirmed } = await this.timedPrompt<{ orgs: OrgAuthorization[]; confirmed: boolean }>( - [ - { - name: 'orgs', - message: messages.getMessage('prompt.select-envs'), - type: 'checkbox', - choices, - loop: true, - }, - { - name: 'confirmed', - when: (answers): boolean => answers.orgs.length > 0, - message: (answers): string => { - const hasScratchOrgs = answers.orgs.some((org) => org.isScratchOrg); - if (hasScratchOrgs) { - this.warn(messages.getMessage('warning')); - } - const names = answers.orgs.map((org) => org.username); - if (names.length === orgAuths.length) { - return messages.getMessage('prompt.confirm-all'); - } else { - return messages.getMessage('prompt.confirm', [names.length, names.length > 1 ? 's' : '']); - } - }, - type: 'confirm', - default: false, - }, - ], - 30_000 - ); - return { - orgs: orgs.map((a) => a), - confirmed, - }; - } -} + if (orgAuth.isSandbox) { + return 'Sandbox'.length; + } + return 0; + }) + ); + const choices = orgAuths + .map((orgAuth) => { + const aliasString = (orgAuth.aliases ? orgAuth.aliases.join(',') : '').padEnd(maxAliasLength, ' '); + const configString = (orgAuth.configs ? orgAuth.configs.join(',') : '').padEnd(maxConfigLength, ' '); + const typeString = chalk.dim( + (orgAuth.isScratchOrg ? 'Scratch' : orgAuth.isDevHub ? 'DevHub' : orgAuth.isSandbox ? 'Sandbox' : '').padEnd( + maxTypeLength, + ' ' + ) + ); + // username - aliases - configs + const key = `${chalk.bold( + orgAuth.username.padEnd(maxUsernameLength) + )} | ${typeString} | ${aliasString} | ${chalk.yellowBright(configString)}`; + return { name: key, value: orgAuth, checked: all, short: `${os.EOL}${orgAuth.username}` }; + }) + .sort((a, b) => a.value.username.localeCompare(b.value.username)); + const userHeader = `${'Username'.padEnd(maxUsernameLength, ' ')}`; + const aliasHeader = `${'Aliases'.padEnd(maxAliasLength, ' ')}`; + const configHeader = `${'Configs'.padEnd(maxConfigLength, ' ')}`; + const typeHeader = `${'Type'.padEnd(maxTypeLength, ' ')}`; + return [new Separator(` ${userHeader} | ${typeHeader} | ${aliasHeader} | ${configHeader}`), ...choices]; +}; diff --git a/src/common.ts b/src/common.ts index 265e41dd..89b77619 100644 --- a/src/common.ts +++ b/src/common.ts @@ -5,36 +5,35 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ - -import { Logger, SfdcUrl, SfProject, Messages, SfError } from '@salesforce/core'; +import { Logger, SfdcUrl, SfProject, Messages, SfError, Global, Mode } from '@salesforce/core'; import { getString, isObject } from '@salesforce/ts-types'; +import chalk from 'chalk'; +import { prompts } from '@salesforce/sf-plugins-core'; -Messages.importMessagesDirectoryFromMetaUrl(import.meta.url) +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); -export class Common { - public static async resolveLoginUrl(instanceUrl?: string): Promise { - const logger = await Logger.child('Common', { tag: 'resolveLoginUrl' }); - if (instanceUrl) { - throwIfLightning(instanceUrl); - return instanceUrl; - } - let loginUrl: string; - try { - const project = await SfProject.resolve(); - const projectJson = await project.resolveProjectConfig(); - loginUrl = getString(projectJson, 'sfdcLoginUrl', SfdcUrl.PRODUCTION); - } catch (err) { - const message: string = (isObject(err) ? Reflect.get(err, 'message') ?? err : err) as string; - logger.debug(`error occurred while trying to determine loginUrl: ${message}`); - loginUrl = SfdcUrl.PRODUCTION; - } - throwIfLightning(loginUrl); - - logger.debug(`loginUrl: ${loginUrl}`); - return loginUrl; +const resolveLoginUrl = async (instanceUrl?: string): Promise => { + const logger = await Logger.child('Common', { tag: 'resolveLoginUrl' }); + if (instanceUrl) { + throwIfLightning(instanceUrl); + return instanceUrl; } -} + let loginUrl: string; + try { + const project = await SfProject.resolve(); + const projectJson = await project.resolveProjectConfig(); + loginUrl = getString(projectJson, 'sfdcLoginUrl', SfdcUrl.PRODUCTION); + } catch (err) { + const message: string = (isObject(err) ? Reflect.get(err, 'message') ?? err : err) as string; + logger.debug(`error occurred while trying to determine loginUrl: ${message}`); + loginUrl = SfdcUrl.PRODUCTION; + } + throwIfLightning(loginUrl); + + logger.debug(`loginUrl: ${loginUrl}`); + return loginUrl; +}; const throwIfLightning = (urlString?: string): void => { if (urlString?.match(/\.lightning\..*force\.com/)) { @@ -43,3 +42,13 @@ const throwIfLightning = (urlString?: string): void => { ]); } }; + +const shouldExitCommand = async (noPrompt?: boolean): Promise => + Boolean(noPrompt) || Global.getEnvironmentMode() !== Mode.DEMO + ? false + : !(await prompts.confirm({ message: chalk.dim(messages.getMessage('warnAuth', ['sf'])), ms: 60_000 })); + +export default { + shouldExitCommand, + resolveLoginUrl, +}; diff --git a/test/commands/org/login/access-token.test.ts b/test/commands/org/login/access-token.test.ts index 91923437..34c5a277 100644 --- a/test/commands/org/login/access-token.test.ts +++ b/test/commands/org/login/access-token.test.ts @@ -5,21 +5,23 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -/* eslint-disable @typescript-eslint/ban-ts-comment */ - -import { AuthFields, AuthInfo, SfError, StateAggregator } from '@salesforce/core'; -import { stubMethod } from '@salesforce/ts-sinon'; +import { AuthFields, AuthInfo, StateAggregator } from '@salesforce/core'; import { assert, expect } from 'chai'; import { TestContext } from '@salesforce/core/lib/testSetup.js'; -import { Env } from '@salesforce/kit'; -import { Config } from '@oclif/core'; +import { stubPrompter, stubSfCommandUx } from '@salesforce/sf-plugins-core'; +import { env } from '@salesforce/kit'; import Store from '../../../../src/commands/org/login/access-token.js'; describe('org:login:access-token', () => { const $$ = new TestContext(); - - let authFields: AuthFields; const accessToken = '00Dxx0000000000!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; + const authFields = { + accessToken, + instanceUrl: 'https://foo.bar.org.salesforce.com', + loginUrl: 'https://foo.bar.org.salesforce.com', + orgId: '00D000000000000', + username: 'foo@baz.org', + } as const satisfies AuthFields; /* eslint-disable camelcase */ const userInfo = { @@ -28,99 +30,103 @@ describe('org:login:access-token', () => { custom_domain: 'https://foo.bar.org.salesforce.com', }; /* eslint-enable camelcase */ + let stubSfCommandUxStubs: ReturnType; + let prompterStubs: ReturnType; - async function createNewStoreCommand( - flags: string[] = [], - promptAnswer = accessToken, - authFileExists = false, - useSfdxAccessTokenEnvVar = false - ): Promise { - authFields = { - accessToken, - instanceUrl: 'https://foo.bar.org.salesforce.com', - loginUrl: 'https://foo.bar.org.salesforce.com', - orgId: '00D000000000000', - username: 'foo@baz.org', - }; - - stubMethod($$.SANDBOX, StateAggregator, 'getInstance').resolves({ - orgs: { - exists: () => Promise.resolve(authFileExists), - }, - }); - stubMethod($$.SANDBOX, Store.prototype, 'saveAuthInfo').resolves(userInfo); - stubMethod($$.SANDBOX, AuthInfo.prototype, 'getUsername').returns(authFields.username); - stubMethod($$.SANDBOX, AuthInfo.prototype, 'getFields').returns({ + beforeEach(() => { + // @ts-expect-error because private method + $$.SANDBOX.stub(Store.prototype, 'saveAuthInfo').resolves(userInfo); + $$.SANDBOX.stub(AuthInfo.prototype, 'getUsername').returns(authFields.username); + $$.SANDBOX.stub(AuthInfo.prototype, 'getFields').returns({ accessToken, orgId: authFields.orgId, instanceUrl: authFields.instanceUrl, loginUrl: authFields.loginUrl, username: authFields.username, }); - stubMethod($$.SANDBOX, Store.prototype, 'getUserInfo').resolves(AuthInfo.prototype); - if (useSfdxAccessTokenEnvVar) { - stubMethod($$.SANDBOX, Env.prototype, 'getString').callsFake(() => accessToken); - } - const store = new Store( - [...new Set(['--instance-url', 'https://foo.bar.org.salesforce.com', '--no-prompt', ...flags])], - {} as Config - ); - // @ts-ignore - $$.SANDBOX.stub(Store.prototype, 'askForAccessToken').resolves(promptAnswer); - - return Promise.resolve(store); - } + // @ts-expect-error because private method + $$.SANDBOX.stub(Store.prototype, 'getUserInfo').resolves(AuthInfo.prototype); + stubSfCommandUxStubs = stubSfCommandUx($$.SANDBOX); + prompterStubs = stubPrompter($$.SANDBOX); + }); it('should return auth fields after successful auth', async () => { - const store = await createNewStoreCommand(['--instance-url', 'https://foo.bar.org.salesforce.com', '--no-prompt']); - const result = await store.run(); - expect(result).to.deep.equal(authFields); - }); + prompterStubs.secret.resolves(accessToken); - it('should prompt for access token when accesstokenfile is not present', async () => { - const store = await createNewStoreCommand(['--instance-url', 'https://foo.bar.org.salesforce.com', '--no-prompt']); - const result = await store.run(); + const result = await Store.run(['--instance-url', 'https://foo.bar.org.salesforce.com']); + expect(prompterStubs.secret.callCount).to.equal(1); + expect(stubSfCommandUxStubs.logSuccess.callCount).to.equal(1); expect(result).to.deep.equal(authFields); }); it('should show invalid access token provided as input', async () => { - const store = await createNewStoreCommand( - ['--instance-url', 'https://foo.bar.org.salesforce.com', '--no-prompt'], - 'invalidaccesstokenformat' - ); + prompterStubs.secret.resolves('invalidaccesstokenformat'); + try { - await store.run(); + await Store.run(['--instance-url', 'https://foo.bar.org.salesforce.com']); assert(false, 'should throw error'); } catch (e) { - const err = e as SfError; - expect(err.message).to.include("The access token isn't in the correct format"); + assert(e instanceof Error); + expect(e.message).to.include("The access token isn't in the correct format"); } + expect(prompterStubs.secret.callCount).to.equal(1); }); it('should show that auth file already exists', async () => { - const store = await createNewStoreCommand( - ['--instance-url', 'https://foo.bar.org.salesforce.com'], - accessToken, - true - ); - await store.run(); + prompterStubs.secret.resolves(accessToken); + prompterStubs.confirm.resolves(false); + $$.SANDBOX.stub(StateAggregator, 'getInstance').resolves({ + // @ts-expect-error because incomplete interface + orgs: { + exists: () => Promise.resolve(true), + }, + }); + const result = await Store.run(['--instance-url', 'https://foo.bar.org.salesforce.com']); + expect(result).to.deep.equal(authFields); + expect(prompterStubs.secret.callCount).to.equal(1); + expect(prompterStubs.confirm.callCount).to.equal(1); }); it('should show that auth file does not already exist', async () => { - const store = await createNewStoreCommand(['--instance-url', 'https://foo.bar.org.salesforce.com'], accessToken); - const result = await store.run(); - // prompt once; one for access token + prompterStubs.secret.resolves(accessToken); + $$.SANDBOX.stub(StateAggregator, 'getInstance').resolves({ + // @ts-expect-error because incomplete interface + orgs: { + exists: () => Promise.resolve(false), + }, + }); + const result = await Store.run(['--instance-url', 'https://foo.bar.org.salesforce.com']); expect(result).to.deep.equal(authFields); + expect(prompterStubs.confirm.callCount).to.equal(0); }); + it('should use env var SF_ACCESS_TOKEN as input to the store command', async () => { - const store = await createNewStoreCommand( - ['--instance-url', 'https://foo.bar.org.salesforce.com'], - accessToken, - false, - true - ); - const result = await store.run(); - // no prompts + $$.SANDBOX.stub(env, 'getString') + .withArgs('SF_ACCESS_TOKEN') + .returns(accessToken) + .withArgs('SFDX_ACCESS_TOKEN') + // @ts-expect-error not sure why TS thinks a string is required. getString can return undefined + .returns(undefined); + + const result = await Store.run(['--instance-url', 'https://foo.bar.org.salesforce.com']); + expect(result).to.deep.equal(authFields); + // no prompts needed when using Env + expect(prompterStubs.confirm.callCount).to.equal(0); + expect(prompterStubs.secret.callCount).to.equal(0); + }); + + it('should use env var SFDX_ACCESS_TOKEN as input to the store command', async () => { + $$.SANDBOX.stub(env, 'getString') + .withArgs('SFDX_ACCESS_TOKEN') + .returns(accessToken) + .withArgs('SF_ACCESS_TOKEN') + // @ts-expect-error not sure why TS thinks a string is required. getString can return undefined + .returns(undefined); + + const result = await Store.run(['--instance-url', 'https://foo.bar.org.salesforce.com']); expect(result).to.deep.equal(authFields); + // no prompts needed when using Env + expect(prompterStubs.confirm.callCount).to.equal(0); + expect(prompterStubs.secret.callCount).to.equal(0); }); }); diff --git a/test/commands/org/login/login.device.test.ts b/test/commands/org/login/login.device.test.ts index 562b959f..aa73161e 100644 --- a/test/commands/org/login/login.device.test.ts +++ b/test/commands/org/login/login.device.test.ts @@ -7,7 +7,7 @@ /* eslint-disable camelcase */ -import { AuthFields, AuthInfo, DeviceOauthService, Global, Mode } from '@salesforce/core'; +import { AuthFields, AuthInfo, DeviceOauthService } from '@salesforce/core'; import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup.js'; import { StubbedType, stubInterface, stubMethod } from '@salesforce/ts-sinon'; import { DeviceCodeResponse } from '@salesforce/core/lib/deviceOauthService.js'; @@ -15,7 +15,6 @@ import { expect } from 'chai'; import { Config } from '@oclif/core'; import { SfCommand } from '@salesforce/sf-plugins-core'; import Login from '../../../../src/commands/org/login/device.js'; - interface Options { approvalTimesout?: boolean; approvalFails?: boolean; @@ -136,29 +135,9 @@ describe('org:login:device', () => { it('should prompt for client secret if client id is provided', async () => { await prepareStubs(); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - $$.SANDBOX.stub(Login.prototype, 'askForHiddenResponse').returns(Promise.resolve('1234')); + $$.SANDBOX.stub(SfCommand.prototype, 'secretPrompt').resolves('1234'); const login = new Login(['-i', 'CoffeeBeans', '--json'], {} as Config); const response = await login.run(); expect(response.username).to.equal(testData.username); }); - - it('should prompt for when in demo mode (SFDX_ENV=demo)', async () => { - await prepareStubs(); - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(true); - const login = new Login(['--json'], {} as Config); - const response = await login.run(); - expect(response.username).to.equal(testData.username); - }); - - it('should exit early when prompt is answered NO', async () => { - await prepareStubs(); - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(false); - const login = new Login(['--json'], {} as Config); - const response = await login.run(); - expect(response).to.deep.equal({}); - }); }); diff --git a/test/commands/org/login/login.jwt.test.ts b/test/commands/org/login/login.jwt.test.ts index 69e39e60..b679e2e4 100644 --- a/test/commands/org/login/login.jwt.test.ts +++ b/test/commands/org/login/login.jwt.test.ts @@ -5,12 +5,11 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { AuthFields, AuthInfo, Global, Mode, SfError } from '@salesforce/core'; +import { AuthFields, AuthInfo, SfError } from '@salesforce/core'; import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup.js'; import { StubbedType, stubInterface } from '@salesforce/ts-sinon'; import { expect } from 'chai'; import { Config } from '@oclif/core'; -import { SfCommand } from '@salesforce/sf-plugins-core'; import LoginJwt from '../../../../src/commands/org/login/jwt.js'; interface Options { @@ -201,39 +200,4 @@ describe('org:login:jwt', () => { expect.fail('Should not have thrown an error'); } }); - - it('should auth when in demo mode (SFDX_ENV=demo) and prompt is answered with yes', async () => { - await prepareStubs(); - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(true); - const grant = new LoginJwt( - ['-u', testData.username, '-f', 'path/to/key.json', '-i', '123456', '--json'], - {} as Config - ); - await grant.run(); - expect(authInfoStub.save.called); - }); - - it('should do nothing when in demo mode (SFDX_ENV=demo) and prompt is answered with no', async () => { - await prepareStubs(); - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(false); - const grant = new LoginJwt( - ['-u', testData.username, '-f', 'path/to/key.json', '-i', '123456', '--json'], - {} as Config - ); - await grant.run(); - expect(authInfoStub.save.callCount).to.equal(0); - }); - - it('should ignore prompt when in demo mode (SFDX_ENV=demo) and -p is provided', async () => { - await prepareStubs(); - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - const grant = new LoginJwt( - ['-p', '-u', testData.username, '-f', 'path/to/key.json', '-i', '123456', '--json'], - {} as Config - ); - await grant.run(); - expect(authInfoStub.save.called); - }); }); diff --git a/test/commands/org/login/login.sfdx-url.test.ts b/test/commands/org/login/login.sfdx-url.test.ts index cdc11ab9..8d727c63 100644 --- a/test/commands/org/login/login.sfdx-url.test.ts +++ b/test/commands/org/login/login.sfdx-url.test.ts @@ -6,12 +6,11 @@ */ import fs from 'node:fs/promises'; -import { AuthFields, AuthInfo, Global, Mode } from '@salesforce/core'; +import { AuthFields, AuthInfo } from '@salesforce/core'; import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup.js'; import { expect } from 'chai'; import { Config } from '@oclif/core'; import { StubbedType, stubInterface, stubMethod } from '@salesforce/ts-sinon'; -import { SfCommand } from '@salesforce/sf-plugins-core'; import LoginSfdxUrl from '../../../../src/commands/org/login/sfdx-url.js'; interface Options { @@ -187,33 +186,6 @@ describe('org:login:sfdx-url', () => { ]); }); - it('should auth when in demo mode (SFDX_ENV=demo) and prompt is answered with yes', async () => { - await prepareStubs(); - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(true); - const store = new LoginSfdxUrl(['-f', keyPathTxt, '--json'], {} as Config); - await store.run(); - expect(authInfoStub.save.called); - }); - - it('should do nothing when in demo mode (SFDX_ENV=demo) and prompt is answered with no', async () => { - await prepareStubs(); - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(false); - const store = new LoginSfdxUrl(['-f', keyPathTxt, '--json'], {} as Config); - await store.run(); - expect(authInfoStub.save.callCount).to.equal(0); - }); - - it('should ignore prompt when in demo mode (SFDX_ENV=demo) and -p is provided', async () => { - await prepareStubs(); - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(false); - const store = new LoginSfdxUrl(['-p', '-f', keyPathTxt, '--json'], {} as Config); - await store.run(); - expect(authInfoStub.save.called); - }); - it('should error out when neither file or url are provided', async () => { await prepareStubs(); const store = new LoginSfdxUrl([], {} as Config); diff --git a/test/commands/org/login/login.web.test.ts b/test/commands/org/login/login.web.test.ts index c599eff7..8e23e556 100644 --- a/test/commands/org/login/login.web.test.ts +++ b/test/commands/org/login/login.web.test.ts @@ -8,7 +8,7 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { Config } from '@oclif/core'; -import { AuthFields, AuthInfo, Global, Mode, SfError } from '@salesforce/core'; +import { AuthFields, AuthInfo, SfError } from '@salesforce/core'; import { MockTestOrgData, TestContext } from '@salesforce/core/lib/testSetup.js'; import { StubbedType, stubInterface, stubMethod } from '@salesforce/ts-sinon'; import { assert, expect } from 'chai'; @@ -30,8 +30,7 @@ describe('org:login:web', () => { clientSecret = '' ): Promise { authFields = await testData.getConfig(); - // @ts-ignore - $$.SANDBOX.stub(LoginWeb.prototype, 'askForClientSecret').resolves(clientSecret); + $$.SANDBOX.stub(SfCommand.prototype, 'secretPrompt').resolves(clientSecret); $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(promptAnswer); authInfoStub = stubInterface($$.SANDBOX, { @@ -116,20 +115,6 @@ describe('org:login:web', () => { await login.run(); }); - it('should exit command if in demo and prompt is answered NO', async () => { - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - const login = await createNewLoginCommand([], false, undefined); - const result = await login.run(); - expect(result).to.deep.equal({}); - }); - - it('should execute command if in demo and prompt is answered YES', async () => { - $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.DEMO); - const login = await createNewLoginCommand([], true, undefined); - const result = await login.run(); - expect(result).to.deep.equal(authFields); - }); - it('should show invalidClientId error if AuthCodeExchangeError', async () => { const login = await createNewLoginCommandWithError('AuthCodeExchangeError'); try { diff --git a/test/commands/org/logout.test.ts b/test/commands/org/logout.test.ts index 55d1d6c5..21fcefba 100644 --- a/test/commands/org/logout.test.ts +++ b/test/commands/org/logout.test.ts @@ -42,6 +42,8 @@ describe('org:logout', () => { if (options['target-org']) { $$.setConfigStubContents('Config', { contents: { 'target-org': options['target-org'] } }); + } else { + $$.setConfigStubContents('Config', { contents: {} }); } if (options.aliases) { diff --git a/test/common.test.ts b/test/common.test.ts index 386cf207..b93a0ceb 100644 --- a/test/common.test.ts +++ b/test/common.test.ts @@ -5,10 +5,10 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ -import { ConfigContents, SfdcUrl } from '@salesforce/core'; +import { ConfigContents, SfdcUrl, Global, Mode } from '@salesforce/core'; import { assert, expect } from 'chai'; import { TestContext, uniqid } from '@salesforce/core/lib/testSetup.js'; -import { Common } from '../src/common.js'; +import common from '../src/common.js'; const projectSetup = async ($$: TestContext, inProject = true, contents?: ConfigContents): Promise => { $$.inProject(inProject); @@ -33,7 +33,7 @@ describe('common unit tests', () => { describe('production url', () => { it('should return production URL if not in a dx project', async () => { await projectSetup($$, false); - const loginUrl = await Common.resolveLoginUrl(undefined); + const loginUrl = await common.resolveLoginUrl(undefined); expect(loginUrl).to.equal(SfdcUrl.PRODUCTION); }); it('should return production URL if project with property sfdcLoginUrl absent', async () => { @@ -46,7 +46,7 @@ describe('common unit tests', () => { ], sourceApiVersion: '50.0', }); - const loginUrl = await Common.resolveLoginUrl(undefined); + const loginUrl = await common.resolveLoginUrl(undefined); expect(loginUrl).to.equal(SfdcUrl.PRODUCTION); }); it('should return production URL if project with property sfdcLoginUrl present', async () => { @@ -60,7 +60,7 @@ describe('common unit tests', () => { sfdcLoginUrl: 'https://login.salesforce.com', sourceApiVersion: '50.0', }); - const loginUrl = await Common.resolveLoginUrl(undefined); + const loginUrl = await common.resolveLoginUrl(undefined); expect(loginUrl).to.equal(SfdcUrl.PRODUCTION); }); it('should throw on lightning login URL in sfdcLoginUrl property', async () => { @@ -75,7 +75,7 @@ describe('common unit tests', () => { sourceApiVersion: '50.0', }); try { - await Common.resolveLoginUrl(undefined); + await common.resolveLoginUrl(undefined); expect.fail('This test is failing because it is expecting an error that is never thrown'); } catch (error) { assert(error instanceof Error); @@ -85,7 +85,7 @@ describe('common unit tests', () => { it('should throw on lightning login URL passed in to resolveLoginUrl()', async () => { await projectSetup($$, true); try { - await Common.resolveLoginUrl('https://shanedevhub.lightning.force.com'); + await common.resolveLoginUrl('https://shanedevhub.lightning.force.com'); expect.fail('This test is failing because it is expecting an error that is never thrown'); } catch (error) { assert(error instanceof Error); @@ -95,14 +95,14 @@ describe('common unit tests', () => { it('should allow a domain containing lightning in its login URL', async () => { await projectSetup($$, true); - const loginUrl = await Common.resolveLoginUrl('https://mycompany-lightning.my.salesforce.com'); + const loginUrl = await common.resolveLoginUrl('https://mycompany-lightning.my.salesforce.com'); expect(loginUrl).equals('https://mycompany-lightning.my.salesforce.com'); }); it('should throw on internal lightning login URL passed in to resolveLoginUrl()', async () => { await projectSetup($$, true); try { - await Common.resolveLoginUrl('https://dro000000osjp2a0.test1.lightning.pc-rnd.force.com/'); + await common.resolveLoginUrl('https://dro000000osjp2a0.test1.lightning.pc-rnd.force.com/'); expect.fail('This test is failing because it is expecting an error that is never thrown'); } catch (error) { assert(error instanceof Error); @@ -116,7 +116,7 @@ describe('common unit tests', () => { it('should return custom login URL if not in a dx project and instance-url given', async () => { await projectSetup($$, false); - const loginUrl = await Common.resolveLoginUrl(INSTANCE_URL_1); + const loginUrl = await common.resolveLoginUrl(INSTANCE_URL_1); expect(loginUrl).to.equal(INSTANCE_URL_1); }); it('should return custom login URL if project with property sfdcLoginUrl absent and instance-url given', async () => { @@ -131,7 +131,7 @@ describe('common unit tests', () => { sourceApiVersion: '50.0', }, }); - const loginUrl = await Common.resolveLoginUrl(INSTANCE_URL_1); + const loginUrl = await common.resolveLoginUrl(INSTANCE_URL_1); expect(loginUrl).to.equal(INSTANCE_URL_1); }); it('should return custom login URL if project with property sfdcLoginUrl present and not equal to production URL', async () => { @@ -145,10 +145,10 @@ describe('common unit tests', () => { sfdcLoginUrl: INSTANCE_URL_2, sourceApiVersion: '50.0', }); - const loginUrl = await Common.resolveLoginUrl(undefined); + const loginUrl = await common.resolveLoginUrl(undefined); expect(loginUrl).to.equal(INSTANCE_URL_2); }); - it('should return custom login URL 1 if project with property sfdcLoginUrl equal to ciustom url 2', async () => { + it('should return custom login URL 1 if project with property sfdcLoginUrl equal to custom url 2', async () => { await projectSetup($$, true, { contents: { packageDirectories: [ @@ -161,8 +161,20 @@ describe('common unit tests', () => { sourceApiVersion: '50.0', }, }); - const loginUrl = await Common.resolveLoginUrl(INSTANCE_URL_1); + const loginUrl = await common.resolveLoginUrl(INSTANCE_URL_1); expect(loginUrl).to.equal(INSTANCE_URL_1); }); }); + + describe('shouldExitCommand', () => { + it('should not exit if noPrompt is true', async () => { + const shouldExit = await common.shouldExitCommand(true); + expect(shouldExit).to.be.false; + }); + it('should not exit if not DEMO mode', async () => { + $$.SANDBOX.stub(Global, 'getEnvironmentMode').returns(Mode.PRODUCTION); + const shouldExit = await common.shouldExitCommand(); + expect(shouldExit).to.be.false; + }); + }); }); diff --git a/tsconfig.json b/tsconfig.json index d024f738..8f514318 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "outDir": "lib", "rootDir": "src", - "strictNullChecks": true + "strictNullChecks": true, + "skipLibCheck": true }, "include": ["./src/**/*.ts"] } diff --git a/yarn.lock b/yarn.lock index 0ebb1c1a..89d70e9b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -445,6 +445,81 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== +"@inquirer/checkbox@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-1.5.0.tgz#05869b4ee81e2c8d523799ef350d57cabd556bfa" + integrity sha512-3cKJkW1vIZAs4NaS0reFsnpAjP0azffYII4I2R7PTI7ZTMg5Y1at4vzXccOH3762b2c2L4drBhpJpf9uiaGNxA== + dependencies: + "@inquirer/core" "^5.1.1" + "@inquirer/type" "^1.1.5" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + figures "^3.2.0" + +"@inquirer/confirm@^2.0.15": + version "2.0.15" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-2.0.15.tgz#b5512ed190efd8c5b96e0969115756b48546ab36" + integrity sha512-hj8Q/z7sQXsF0DSpLQZVDhWYGN6KLM/gNjjqGkpKwBzljbQofGjn0ueHADy4HUY+OqDHmXuwk/bY+tZyIuuB0w== + dependencies: + "@inquirer/core" "^5.1.1" + "@inquirer/type" "^1.1.5" + chalk "^4.1.2" + +"@inquirer/core@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-5.1.1.tgz#849d4846aea68371c133df6ec9059f5e5bd30d30" + integrity sha512-IuJyZQUg75+L5AmopgnzxYrgcU6PJKL0hoIs332G1Gv55CnmZrhG6BzNOeZ5sOsTi1YCGOopw4rYICv74ejMFg== + dependencies: + "@inquirer/type" "^1.1.5" + "@types/mute-stream" "^0.0.4" + "@types/node" "^20.9.0" + "@types/wrap-ansi" "^3.0.0" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + cli-spinners "^2.9.1" + cli-width "^4.1.0" + figures "^3.2.0" + mute-stream "^1.0.0" + run-async "^3.0.0" + signal-exit "^4.1.0" + strip-ansi "^6.0.1" + wrap-ansi "^6.2.0" + +"@inquirer/input@^1.2.14": + version "1.2.14" + resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-1.2.14.tgz#8951867618bb5cd16dd096e02404eec225a92207" + integrity sha512-tISLGpUKXixIQue7jypNEShrdzJoLvEvZOJ4QRsw5XTfrIYfoWFqAjMQLerGs9CzR86yAI89JR6snHmKwnNddw== + dependencies: + "@inquirer/core" "^5.1.1" + "@inquirer/type" "^1.1.5" + chalk "^4.1.2" + +"@inquirer/password@^1.1.14": + version "1.1.14" + resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-1.1.14.tgz#c1fc139efe84a38986870a1bcf80718050f82bbf" + integrity sha512-vL2BFxfMo8EvuGuZYlryiyAB3XsgtbxOcFs4H9WI9szAS/VZCAwdVqs8rqEeaAf/GV/eZOghIOYxvD91IsRWSg== + dependencies: + "@inquirer/input" "^1.2.14" + "@inquirer/type" "^1.1.5" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + +"@inquirer/select@^1.3.1": + version "1.3.1" + resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-1.3.1.tgz#b10bb8d4ba72f08eb887b3d948eb734d680897c6" + integrity sha512-EgOPHv7XOHEqiBwBJTyiMg9r57ySyW4oyYCumGp+pGyOaXQaLb2kTnccWI6NFd9HSi5kDJhF7YjA+3RfMQJ2JQ== + dependencies: + "@inquirer/core" "^5.1.1" + "@inquirer/type" "^1.1.5" + ansi-escapes "^4.3.2" + chalk "^4.1.2" + figures "^3.2.0" + +"@inquirer/type@^1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-1.1.5.tgz#b8c171f755859c8159b10e41e1e3a88f0ca99d7f" + integrity sha512-wmwHvHozpPo4IZkkNtbYenem/0wnfI6hvOcGKmPEa0DwuaH5XUQzFqy6OpEpjEegZMhYIk8HDYITI16BPLtrRA== + "@isaacs/cliui@^8.0.2": version "8.0.2" resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" @@ -693,55 +768,10 @@ node-gyp "^8.2.0" read-package-json-fast "^2.0.1" -"@oclif/color@^1.0.8": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@oclif/color/-/color-1.0.9.tgz#9707f0cd39b3c2eae0eb0c76a90838a594306327" - integrity sha512-ntc/fZwuf4NRfYbXVoUNFyMB9IxVx/ls/WbSLKbkD9UpsmwY1I3J4DJKKRFRpenmTuxGQW8Lyzm7X3vhzHpDQA== - dependencies: - ansi-styles "^4.2.1" - chalk "^4.1.0" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - tslib "^2" - -"@oclif/core@^2.9.3": - version "2.15.0" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-2.15.0.tgz#f27797b30a77d13279fba88c1698fc34a0bd0d2a" - integrity sha512-fNEMG5DzJHhYmI3MgpByTvltBOMyFcnRIUMxbiz2ai8rhaYgaTHMG3Q38HcosfIvtw9nCjxpcQtC8MN8QtVCcA== - dependencies: - "@types/cli-progress" "^3.11.0" - ansi-escapes "^4.3.2" - ansi-styles "^4.3.0" - cardinal "^2.1.1" - chalk "^4.1.2" - clean-stack "^3.0.1" - cli-progress "^3.12.0" - debug "^4.3.4" - ejs "^3.1.8" - get-package-type "^0.1.0" - globby "^11.1.0" - hyperlinker "^1.0.0" - indent-string "^4.0.0" - is-wsl "^2.2.0" - js-yaml "^3.14.1" - natural-orderby "^2.0.3" - object-treeify "^1.1.33" - password-prompt "^1.1.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - supports-color "^8.1.1" - supports-hyperlinks "^2.2.0" - ts-node "^10.9.1" - tslib "^2.5.0" - widest-line "^3.1.0" - wordwrap "^1.0.0" - wrap-ansi "^7.0.0" - -"@oclif/core@^3.0.4", "@oclif/core@^3.15.0", "@oclif/core@^3.15.1", "@oclif/core@^3.16.0", "@oclif/core@^3.3.1": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@oclif/core/-/core-3.16.0.tgz#682657cb5e4a3262a47e26e0c8a7bf0343acaf76" - integrity sha512-/PIz+udzb59XE8O/bQvqlCtXy6RByEHH0KsrAJNa/ZrqtdsLmeDNJcHdgygFHx+nz+PYMoUzsyzJMau++EDNoQ== +"@oclif/core@^3.15.0", "@oclif/core@^3.15.1", "@oclif/core@^3.16.0", "@oclif/core@^3.18.0": + version "3.18.0" + resolved "https://registry.yarnpkg.com/@oclif/core/-/core-3.18.0.tgz#3f594d2509d9b4e8981f0b6b1a318826979dd2f2" + integrity sha512-xPuN3kT87WXHvkyZIrPyp87VLIEkreQqVpCIcLtIGjZ0a7/0c7c4j6NjGApHp5rz/5lprW/i1FPt3IvrrNlMeA== dependencies: ansi-escapes "^4.3.2" ansi-styles "^4.3.0" @@ -766,7 +796,6 @@ strip-ansi "^6.0.1" supports-color "^8.1.1" supports-hyperlinks "^2.2.0" - tsconfck "^3.0.0" widest-line "^3.1.0" wordwrap "^1.0.0" wrap-ansi "^7.0.0" @@ -786,28 +815,28 @@ semver "^7.5.4" ts-json-schema-generator "^1.5.0" -"@oclif/plugin-help@^5.2.14": - version "5.2.14" - resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-5.2.14.tgz#c89f623712fc7d74f01fd2c9d909434b335a2e7b" - integrity sha512-7hMLc6zqxeRfG4nvHHQPpbaBj60efM3ULFkCpHZkdLms/ezIkNo40F661QuraIjMP/NN+U6VSfBCGuPkRyxVkA== +"@oclif/plugin-help@^6.0.9": + version "6.0.10" + resolved "https://registry.yarnpkg.com/@oclif/plugin-help/-/plugin-help-6.0.10.tgz#3a38e94a3f431a2b398679a433ace76a2d0c320d" + integrity sha512-vgAcEVtwsI49H/TllBL/7YlQvUSjR3+nVxb0ipSmbHbEUw5p5q6fcNc3R+N9JHvaa4tc8tjyg35APZAKSaM6xw== dependencies: - "@oclif/core" "^2.9.3" + "@oclif/core" "^3.16.0" -"@oclif/plugin-not-found@^2.3.32": - version "2.3.32" - resolved "https://registry.yarnpkg.com/@oclif/plugin-not-found/-/plugin-not-found-2.3.32.tgz#4b9371b028ed6a74238a5ea7c12cfa7d30d7d0a8" - integrity sha512-tVFHfR9XRUWrcxBugHjFr7HUmbLheDX05IaFr7fMF2hcvcqDs3DBjy42WKEoXSaBVTcST6KKhoSy2UVX8pk9Fg== +"@oclif/plugin-not-found@^3.0.7": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@oclif/plugin-not-found/-/plugin-not-found-3.0.8.tgz#d694a9308993703a1cbacbab7f5625315f0169ea" + integrity sha512-sfh7jFc+1vFsF/+9ghF3pVul9xFJ4Hu1JI+KzkDjgWkfVSyPSEE+s6Hfn2z6lCXkwSKQ5lJATuZmafnGes7NGg== dependencies: - "@oclif/color" "^1.0.8" - "@oclif/core" "^2.9.3" + "@oclif/core" "^3.16.0" + chalk "^5.3.0" fast-levenshtein "^3.0.0" -"@oclif/plugin-warn-if-update-available@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.0.2.tgz#76d02069c0d5545b5000660460edb6085272cbcd" - integrity sha512-dUXfRNFtnezS4uqQ+Ap4qb6UP0DWExTvoqghNvvGTIN4PEgfYHogvBORn+rFnDXXE8kgZFuqP4ZQJRP9NyLhOA== +"@oclif/plugin-warn-if-update-available@^3.0.8": + version "3.0.9" + resolved "https://registry.yarnpkg.com/@oclif/plugin-warn-if-update-available/-/plugin-warn-if-update-available-3.0.9.tgz#f4346f4040adf71d0a120381de2fe4c8411896fd" + integrity sha512-6XjYNJWWu6B4LyW73hzuM9Ihb23WamrABZhwYVJTVMBHdU30pRa1i3rvHCPfmn5c4iv8ZXudS/0zCNuhR121ng== dependencies: - "@oclif/core" "^3.3.1" + "@oclif/core" "^3.16.0" chalk "^5.3.0" debug "^4.1.0" http-call "^5.2.2" @@ -934,10 +963,10 @@ strip-ansi "6.0.1" ts-retry-promise "^0.7.1" -"@salesforce/core@^6.4.0", "@salesforce/core@^6.4.1", "@salesforce/core@^6.4.2", "@salesforce/core@^6.4.4": - version "6.4.4" - resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-6.4.4.tgz#e96d2ef9cd05c3894578374d1054af80bfdca119" - integrity sha512-VegX3ChnJUOOztSP05QPiXCTOSioShB22NyhYjL7vVhf6yqSOH0VT2oQ3ywrMYbYCbjLSdsmFdTVLiQIFpK57g== +"@salesforce/core@^6.4.1", "@salesforce/core@^6.4.2", "@salesforce/core@^6.4.4", "@salesforce/core@^6.4.6": + version "6.4.6" + resolved "https://registry.yarnpkg.com/@salesforce/core/-/core-6.4.6.tgz#f3a8992326c54a341c78cf2abccd8f7dd10ff9ec" + integrity sha512-QMyzLgjZ47rsRuCG4akftdVsxlB8wvF8ITj+RXNLkjIdu+y5tRTn13N9I5TD9TIwotweVBJMcgx6qiwhInFrnw== dependencies: "@salesforce/kit" "^3.0.15" "@salesforce/schemas" "^1.6.1" @@ -1003,13 +1032,13 @@ "@salesforce/ts-types" "^2.0.9" tslib "^2.6.2" -"@salesforce/plugin-command-reference@^3.0.59": - version "3.0.59" - resolved "https://registry.yarnpkg.com/@salesforce/plugin-command-reference/-/plugin-command-reference-3.0.59.tgz#309dba84ae01828e1b8d62d80390240418688c43" - integrity sha512-8mjPJyxz1FF6Ei7RwjMLHZTmFX2+bOOh5aq7lNwk3qkSqy5cSTW8bf+1/lcOPkm2125qCbAUL0wAgAyNACF6Xg== +"@salesforce/plugin-command-reference@^3.0.61": + version "3.0.61" + resolved "https://registry.yarnpkg.com/@salesforce/plugin-command-reference/-/plugin-command-reference-3.0.61.tgz#3f7cd5089b52eed02059d5b6831349913b092f7c" + integrity sha512-0mS90XJW8UaWDaf+bGz0digHjUz69nEZJkYV6UJ/TliYciHlGX3GZT/pRG0rEvnNvggIdcSbdZrq6IP9xyZoVg== dependencies: - "@oclif/core" "^3.15.1" - "@salesforce/core" "^6.4.1" + "@oclif/core" "^3.16.0" + "@salesforce/core" "^6.4.4" "@salesforce/kit" "^3.0.15" "@salesforce/sf-plugins-core" "^5.0.13" "@salesforce/ts-types" "^2.0.9" @@ -1040,6 +1069,19 @@ chalk "^4" inquirer "^8.2.5" +"@salesforce/sf-plugins-core@^7.1.1": + version "7.1.1" + resolved "https://registry.yarnpkg.com/@salesforce/sf-plugins-core/-/sf-plugins-core-7.1.1.tgz#195b14d8bbb5ee2123872775110892c54c08c791" + integrity sha512-stVcdLNaroS8UbcTQicr0aVH7K3yfpMFcPpTpLn2Z7OL66iEhBg4Vtr9+v0qKBjA5ZW7S0M1zzrgjY3ZNRJSxw== + dependencies: + "@inquirer/confirm" "^2.0.15" + "@inquirer/password" "^1.1.14" + "@oclif/core" "^3.16.0" + "@salesforce/core" "^6.4.6" + "@salesforce/kit" "^3.0.15" + "@salesforce/ts-types" "^2.0.9" + chalk "^5.3.0" + "@salesforce/ts-sinon@^1.4.19": version "1.4.19" resolved "https://registry.yarnpkg.com/@salesforce/ts-sinon/-/ts-sinon-1.4.19.tgz#64157b6c8cf4a3c637867e2ddd90c2d058c334f7" @@ -1165,13 +1207,6 @@ resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== -"@types/cli-progress@^3.11.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@types/cli-progress/-/cli-progress-3.11.0.tgz#ec79df99b26757c3d1c7170af8422e0fc95eef7e" - integrity sha512-XhXhBv1R/q2ahF3BM7qT5HLzJNlIL0wbcGyZVjqOTqAybAnsLisd7gy1UCyIqpL+5Iv6XhlSyzjLCnI2sIdbCg== - dependencies: - "@types/node" "*" - "@types/expect@^1.20.4": version "1.20.4" resolved "https://registry.yarnpkg.com/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5" @@ -1247,10 +1282,17 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b" integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== -"@types/node@*", "@types/node@^18": - version "18.18.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.8.tgz#2b285361f2357c8c8578ec86b5d097c7f464cfd6" - integrity sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ== +"@types/mute-stream@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" + integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@^20.9.0": + version "20.10.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.6.tgz#a3ec84c22965802bf763da55b2394424f22bfbb5" + integrity sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw== dependencies: undici-types "~5.26.4" @@ -1264,6 +1306,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== +"@types/node@^18": + version "18.18.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.8.tgz#2b285361f2357c8c8578ec86b5d097c7f464cfd6" + integrity sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ== + dependencies: + undici-types "~5.26.4" + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -1321,6 +1370,11 @@ "@types/expect" "^1.20.4" "@types/node" "*" +"@types/wrap-ansi@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" + integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== + "@typescript-eslint/eslint-plugin@^6.10.0": version "6.11.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.11.0.tgz#52aae65174ff526576351f9ccd41cea01001463f" @@ -1357,13 +1411,13 @@ "@typescript-eslint/types" "6.11.0" "@typescript-eslint/visitor-keys" "6.11.0" -"@typescript-eslint/scope-manager@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.16.0.tgz#f3e9a00fbc1d0701356359cd56489c54d9e37168" - integrity sha512-0N7Y9DSPdaBQ3sqSCwlrm9zJwkpOuc6HYm7LpzLAPqBL7dmzAUimr4M29dMkOP/tEwvOCC/Cxo//yOfJD3HUiw== +"@typescript-eslint/scope-manager@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz#28c31c60f6e5827996aa3560a538693cb4bd3848" + integrity sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw== dependencies: - "@typescript-eslint/types" "6.16.0" - "@typescript-eslint/visitor-keys" "6.16.0" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" "@typescript-eslint/type-utils@6.11.0": version "6.11.0" @@ -1380,10 +1434,10 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.11.0.tgz#8ad3aa000cbf4bdc4dcceed96e9b577f15e0bf53" integrity sha512-ZbEzuD4DwEJxwPqhv3QULlRj8KYTAnNsXxmfuUXFCxZmO6CF2gM/y+ugBSAQhrqaJL3M+oe4owdWunaHM6beqA== -"@typescript-eslint/types@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.16.0.tgz#a3abe0045737d44d8234708d5ed8fef5d59dc91e" - integrity sha512-hvDFpLEvTJoHutVl87+MG/c5C8I6LOgEx05zExTSJDEVU7hhR3jhV8M5zuggbdFCw98+HhZWPHZeKS97kS3JoQ== +"@typescript-eslint/types@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.18.1.tgz#91617d8080bcd99ac355d9157079970d1d49fefc" + integrity sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw== "@typescript-eslint/typescript-estree@6.11.0": version "6.11.0" @@ -1398,13 +1452,13 @@ semver "^7.5.4" ts-api-utils "^1.0.1" -"@typescript-eslint/typescript-estree@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.16.0.tgz#d6e0578e4f593045f0df06c4b3a22bd6f13f2d03" - integrity sha512-VTWZuixh/vr7nih6CfrdpmFNLEnoVBF1skfjdyGnNwXOH1SLeHItGdZDHhhAIzd3ACazyY2Fg76zuzOVTaknGA== +"@typescript-eslint/typescript-estree@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz#a12b6440175b4cbc9d09ab3c4966c6b245215ab4" + integrity sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA== dependencies: - "@typescript-eslint/types" "6.16.0" - "@typescript-eslint/visitor-keys" "6.16.0" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/visitor-keys" "6.18.1" debug "^4.3.4" globby "^11.1.0" is-glob "^4.0.3" @@ -1425,17 +1479,17 @@ "@typescript-eslint/typescript-estree" "6.11.0" semver "^7.5.4" -"@typescript-eslint/utils@^6.13.2", "@typescript-eslint/utils@^6.7.5": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.16.0.tgz#1c291492d34670f9210d2b7fcf6b402bea3134ae" - integrity sha512-T83QPKrBm6n//q9mv7oiSvy/Xq/7Hyw9SzSEhMHJwznEmQayfBM87+oAlkNAMEO7/MjIwKyOHgBJbxB0s7gx2A== +"@typescript-eslint/utils@^6.17.0", "@typescript-eslint/utils@^6.7.5": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.18.1.tgz#3451cfe2e56babb6ac657e10b6703393d4b82955" + integrity sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ== dependencies: "@eslint-community/eslint-utils" "^4.4.0" "@types/json-schema" "^7.0.12" "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.16.0" - "@typescript-eslint/types" "6.16.0" - "@typescript-eslint/typescript-estree" "6.16.0" + "@typescript-eslint/scope-manager" "6.18.1" + "@typescript-eslint/types" "6.18.1" + "@typescript-eslint/typescript-estree" "6.18.1" semver "^7.5.4" "@typescript-eslint/visitor-keys@6.11.0": @@ -1446,12 +1500,12 @@ "@typescript-eslint/types" "6.11.0" eslint-visitor-keys "^3.4.1" -"@typescript-eslint/visitor-keys@6.16.0": - version "6.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.16.0.tgz#d50da18a05d91318ed3e7e8889bda0edc35f3a10" - integrity sha512-QSFQLruk7fhs91a/Ep/LqRdbJCZ1Rq03rqBdKT5Ky17Sz8zRLUksqIe9DW0pKtg/Z35/ztbLQ6qpOCN6rOC11A== +"@typescript-eslint/visitor-keys@6.18.1": + version "6.18.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz#704d789bda2565a15475e7d22f145b8fe77443f4" + integrity sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA== dependencies: - "@typescript-eslint/types" "6.16.0" + "@typescript-eslint/types" "6.18.1" eslint-visitor-keys "^3.4.1" "@ungap/structured-clone@^1.2.0": @@ -1579,7 +1633,7 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.2.1, ansi-styles@^4.3.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0, ansi-styles@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -2232,10 +2286,10 @@ cli-progress@^3.12.0: dependencies: string-width "^4.2.3" -cli-spinners@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" - integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== +cli-spinners@^2.5.0, cli-spinners@^2.9.1: + version "2.9.2" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.9.2.tgz#1773a8f4b9c4d6ac31563df53b3fc1d79462fe41" + integrity sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg== cli-table@^0.3.1: version "0.3.11" @@ -2249,6 +2303,11 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -3060,13 +3119,13 @@ eslint-plugin-perfectionist@^2.1.0: minimatch "^9.0.3" natural-compare-lite "^1.4.0" -eslint-plugin-sf-plugin@^1.17.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-sf-plugin/-/eslint-plugin-sf-plugin-1.17.0.tgz#9a7e81cb63bc6f36aae7c7797f95e2179def7fd3" - integrity sha512-grW7leP0FJbKQZgDjBZanLSTYrus0itKaEmoflEuqTZSyqH4feP53rHby5ysbOnw9OvgZfuq9NSc0a/CzcIbtQ== +eslint-plugin-sf-plugin@^1.17.1: + version "1.17.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-sf-plugin/-/eslint-plugin-sf-plugin-1.17.1.tgz#085119cb27d856170c0651c0d0abbd25493a22d6" + integrity sha512-ZbIC0P5W7enSMNWZYTKKMzQ+yAU8FyWKazdOwk2rMrMEVk+LA23lfKcgCEvvuala718TEkqkPTwPYyn7qujPkA== dependencies: - "@salesforce/core" "^6.4.0" - "@typescript-eslint/utils" "^6.13.2" + "@salesforce/core" "^6.4.4" + "@typescript-eslint/utils" "^6.17.0" eslint-plugin-unicorn@^49.0.0: version "49.0.0" @@ -3341,7 +3400,7 @@ faye@^1.4.0: tough-cookie "*" tunnel-agent "*" -figures@^3.0.0: +figures@^3.0.0, figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== @@ -5390,6 +5449,11 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mute-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== + nanoid@3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" @@ -5712,15 +5776,15 @@ object.values@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" -oclif@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/oclif/-/oclif-4.1.0.tgz#486004caf6da8af9f5bdda681a616b5b2c180b45" - integrity sha512-4E6z1HOdUYXHu/cbbSv0gnbFJfR9BGc9Oa+e9l8SkRoicGnrEPMpuZyY2vxWPGwMndN6ijxxuFlVmw1/j+MJpg== +oclif@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/oclif/-/oclif-4.2.0.tgz#713b098704fbbf6ec59ffaae9af2167038434869" + integrity sha512-pqfc1R+tDNxlViQ6xYf79lGwMr7Erq2Bo4A5p5jMwJrbpHpIunsZXGifZV6V2f4wUTo1dcqjxP6Be8LmeI3Czw== dependencies: - "@oclif/core" "^3.0.4" - "@oclif/plugin-help" "^5.2.14" - "@oclif/plugin-not-found" "^2.3.32" - "@oclif/plugin-warn-if-update-available" "^3.0.0" + "@oclif/core" "^3.16.0" + "@oclif/plugin-help" "^6.0.9" + "@oclif/plugin-not-found" "^3.0.7" + "@oclif/plugin-warn-if-update-available" "^3.0.8" async-retry "^1.3.3" aws-sdk "^2.1231.0" change-case "^4" @@ -5982,7 +6046,7 @@ pascal-case@^3.1.2: no-case "^3.0.4" tslib "^2.0.3" -password-prompt@^1.1.2, password-prompt@^1.1.3: +password-prompt@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/password-prompt/-/password-prompt-1.1.3.tgz#05e539f4e7ca4d6c865d479313f10eb9db63ee5f" integrity sha512-HkrjG2aJlvF0t2BMH0e2LB/EHf3Lcq3fNMzy4GYHcQblAvOl+QQji1Lx7WRBMqpVK8p+KR7bCg7oqAMXtdgqyw== @@ -6543,6 +6607,11 @@ run-async@^2.0.0, run-async@^2.4.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-async@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-3.0.0.tgz#42a432f6d76c689522058984384df28be379daad" + integrity sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -6760,7 +6829,7 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== -signal-exit@^4.0.1: +signal-exit@^4.0.1, signal-exit@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== @@ -7234,7 +7303,7 @@ ts-json-schema-generator@^1.5.0: safe-stable-stringify "^2.4.3" typescript "~5.3.2" -ts-node@^10.8.1, ts-node@^10.9.1, ts-node@^10.9.2: +ts-node@^10.8.1, ts-node@^10.9.2: version "10.9.2" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== @@ -7258,11 +7327,6 @@ ts-retry-promise@^0.7.1: resolved "https://registry.yarnpkg.com/ts-retry-promise/-/ts-retry-promise-0.7.1.tgz#176d6eee6415f07b6c7c286d3657355e284a6906" integrity sha512-NhHOCZ2AQORvH42hOPO5UZxShlcuiRtm7P2jIq2L2RY3PBxw2mLnUsEdHrIslVBFya1v5aZmrR55lWkzo13LrQ== -tsconfck@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-3.0.0.tgz#b469f1ced12973bbec3209a55ed8de3bb04223c9" - integrity sha512-w3wnsIrJNi7avf4Zb0VjOoodoO0woEqGgZGQm+LHH9przdUI+XDKsWAXwxHA1DaRTjeuZNcregSzr7RaA8zG9A== - tsconfig-paths@^3.14.2: version "3.14.2" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088" @@ -7278,7 +7342,7 @@ tslib@^1.9.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.5.0, tslib@^2.6.1, tslib@^2.6.2: +tslib@^2, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.6.1, tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==