diff --git a/README.md b/README.md index c8c2f8de..f1a0ff28 100644 --- a/README.md +++ b/README.md @@ -275,7 +275,7 @@ ALIASES $ sf auth jwt grant EXAMPLES - Log into an org with username jdoe@example.org and on the default instance URL (https://login.salesforce.org). The + Log into an org with username jdoe@example.org and on the default instance URL (https://login.salesforce.com). The private key is stored in the file /Users/jdoe/JWT/server.key and the command uses the connected app with consumer key (client id) 04580y4051234051. diff --git a/command-snapshot.json b/command-snapshot.json index 6c698b13..5c2a190e 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": [ @@ -101,7 +92,6 @@ "alias", "browser", "client-id", - "disable-masking", "instance-url", "json", "loglevel", diff --git a/messages/jwt.grant.md b/messages/jwt.grant.md index d0bb8458..aaa05457 100644 --- a/messages/jwt.grant.md +++ b/messages/jwt.grant.md @@ -20,7 +20,7 @@ We recommend that you set an alias when you log into an org. Aliases make it eas # examples -- Log into an org with username jdoe@example.org and on the default instance URL (https://login.salesforce.org). The private key is stored in the file /Users/jdoe/JWT/server.key and the command uses the connected app with consumer key (client id) 04580y4051234051. +- Log into an org with username jdoe@example.org and on the default instance URL (https://login.salesforce.com). The private key is stored in the file /Users/jdoe/JWT/server.key and the command uses the connected app with consumer key (client id) 04580y4051234051. <%= config.bin %> <%= command.id %> --username jdoe@example.org --jwt-key-file /Users/jdoe/JWT/server.key --client-id 04580y4051234051 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 f4aa7264..d1f817e7 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "author": "Salesforce", "bugs": "https://github.com/forcedotcom/cli/issues", "dependencies": { + "@inquirer/confirm": "^2.0.15", + "@inquirer/password": "^1.1.14", "@oclif/core": "^3.15.0", "@salesforce/core": "^6.4.2", "@salesforce/kit": "^3.0.15", @@ -219,7 +221,7 @@ "output": [] }, "link-check": { - "command": "node -e \"process.exit(process.env.CI ? 0 : 1)\" || linkinator \"**/*.md\" --skip \"CHANGELOG.md|node_modules|test/|confluence.internal.salesforce.com|%s\" --markdown --retry --directory-listing --verbosity error", + "command": "node -e \"process.exit(process.env.CI ? 0 : 1)\" || linkinator \"**/*.md\" --skip \"CHANGELOG.md|node_modules|test/|confluence.internal.salesforce.com|my.salesforce.com|%s\" --markdown --retry --directory-listing --verbosity error", "files": [ "./*.md", "./!(CHANGELOG).md", 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/login/access-token.ts b/src/commands/org/login/access-token.ts index c952e7ae..d773dd38 100644 --- a/src/commands/org/login/access-token.ts +++ b/src/commands/org/login/access-token.ts @@ -5,26 +5,24 @@ * 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 common from '../../../common.js'; -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({ @@ -72,7 +70,7 @@ export default class LoginAccessToken extends AuthBaseCommand { const { flags } = await this.parse(LoginAccessToken); this.flags = flags; const instanceUrl = flags['instance-url'].href; - const accessToken = await this.getAccessToken(); + const accessToken = await getAccessToken(); const authInfo = await this.getUserInfo(accessToken, instanceUrl); return this.storeAuthFromAccessToken(authInfo); } @@ -114,14 +112,14 @@ export default class LoginAccessToken extends AuthBaseCommand { } return true; } +} - private async getAccessToken(): Promise { - const accessToken = - env.getString('SF_ACCESS_TOKEN') ?? env.getString('SFDX_ACCESS_TOKEN') ?? (await this.askForAccessToken()); +const getAccessToken = async (): Promise => { + const accessToken = + env.getString('SF_ACCESS_TOKEN') ?? env.getString('SFDX_ACCESS_TOKEN') ?? (await common.accessTokenPrompt()); - if (!matchesAccessToken(accessToken)) { - throw new SfError(messages.getMessage('invalidAccessTokenFormat', [ACCESS_TOKEN_FORMAT])); - } - return accessToken; + if (!matchesAccessToken(accessToken)) { + throw new SfError(messages.getMessage('invalidAccessTokenFormat', [ACCESS_TOKEN_FORMAT])); } -} + return accessToken; +}; diff --git a/src/commands/org/login/device.ts b/src/commands/org/login/device.ts index 9e4ff604..588b59be 100644 --- a/src/commands/org/login/device.ts +++ b/src/commands/org/login/device.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 { 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) +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'device.login'); const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); 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 flags = { 'client-id': Flags.string({ @@ -58,21 +55,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 5b1d781c..9c37b42d 100644 --- a/src/commands/org/login/jwt.ts +++ b/src/commands/org/login/jwt.ts @@ -5,26 +5,24 @@ * 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) +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 flags = { username: Flags.string({ + // eslint-disable-next-line sf-plugin/dash-o char: 'o', summary: messages.getMessage('flags.username.summary'), required: true, @@ -88,7 +86,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(); @@ -117,7 +115,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 7945a9b9..83bc208f 100644 --- a/src/commands/org/login/sfdx-url.ts +++ b/src/commands/org/login/sfdx-url.ts @@ -5,16 +5,14 @@ * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause */ - - 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) +Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('@salesforce/plugin-auth', 'sfdxurl.store'); const commonMessages = Messages.loadMessages('@salesforce/plugin-auth', 'messages'); @@ -24,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 flags = { 'sfdx-url-file': Flags.file({ @@ -69,7 +67,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']; diff --git a/src/commands/org/login/web.ts b/src/commands/org/login/web.ts index 2e1ecae1..ce59e106 100644 --- a/src/commands/org/login/web.ts +++ b/src/commands/org/login/web.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 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) +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'); public static readonly deprecateAliases = true; - public static aliases = ['force:auth:web:login', 'auth:web:login']; + public static readonly aliases = ['force:auth:web:login', 'auth:web:login']; public static readonly flags = { browser: Flags.string({ @@ -64,12 +61,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'), @@ -90,17 +81,14 @@ export default class LoginWeb extends AuthBaseCommand { 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 common.clientSecretPrompt() } : {}), }; - if (flags['client-id']) { - oauthConfig.clientSecret = await this.askForClientSecret(flags['disable-masking']); - } - try { const authInfo = await this.executeLoginFlow(oauthConfig); await authInfo.handleAliasAndDefaultSettings({ @@ -115,12 +103,11 @@ 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; } } diff --git a/src/commands/org/logout.ts b/src/commands/org/logout.ts index f13e92df..8d162358 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 { Flags, loglevel, Separator, SfCommand } from '@salesforce/sf-plugins-core'; import { Interfaces } from '@oclif/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({ diff --git a/src/common.ts b/src/common.ts index 265e41dd..2ecb8b45 100644 --- a/src/common.ts +++ b/src/common.ts @@ -5,36 +5,36 @@ * 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 password from '@inquirer/password'; +import confirm from '@inquirer/confirm'; -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 +43,20 @@ const throwIfLightning = (urlString?: string): void => { ]); } }; + +const clientSecretPrompt = async (): Promise => + password({ message: chalk.dim(messages.getMessage('clientSecretStdin')) }); +const accessTokenPrompt = async (): Promise => + password({ message: chalk.dim(messages.getMessage('accessTokenStdin')) }); + +const shouldExitCommand = async (noPrompt?: boolean): Promise => + Boolean(noPrompt) || Global.getEnvironmentMode() !== Mode.DEMO + ? false + : !(await confirm({ message: chalk.dim(messages.getMessage('warnAuth', ['sf'])) })); + +export default { + clientSecretPrompt, + accessTokenPrompt, + shouldExitCommand, + resolveLoginUrl, +}; diff --git a/test/commands/org/login/access-token.test.ts b/test/commands/org/login/access-token.test.ts index 91923437..e318ec56 100644 --- a/test/commands/org/login/access-token.test.ts +++ b/test/commands/org/login/access-token.test.ts @@ -8,17 +8,17 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { AuthFields, AuthInfo, SfError, StateAggregator } from '@salesforce/core'; -import { stubMethod } from '@salesforce/ts-sinon'; import { assert, expect } from 'chai'; import { TestContext } from '@salesforce/core/lib/testSetup.js'; import { Env } from '@salesforce/kit'; import { Config } from '@oclif/core'; import Store from '../../../../src/commands/org/login/access-token.js'; +import common from '../../../../src/common.js'; describe('org:login:access-token', () => { const $$ = new TestContext(); - let authFields: AuthFields; + let authFields: Required>; const accessToken = '00Dxx0000000000!xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'; /* eslint-disable camelcase */ @@ -43,30 +43,32 @@ describe('org:login:access-token', () => { username: 'foo@baz.org', }; - stubMethod($$.SANDBOX, StateAggregator, 'getInstance').resolves({ + $$.SANDBOX.stub(StateAggregator, 'getInstance').resolves({ + // @ts-expect-error because incomplete interface 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({ + // @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); + // @ts-expect-error because private method + $$.SANDBOX.stub(Store.prototype, 'getUserInfo').resolves(AuthInfo.prototype); if (useSfdxAccessTokenEnvVar) { - stubMethod($$.SANDBOX, Env.prototype, 'getString').callsFake(() => accessToken); + $$.SANDBOX.stub(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); + $$.SANDBOX.stub(common, 'accessTokenPrompt').resolves(promptAnswer); return Promise.resolve(store); } diff --git a/test/commands/org/login/login.device.test.ts b/test/commands/org/login/login.device.test.ts index 562b959f..0aa59710 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,7 @@ 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'; - +import common from '../../../../src/common.js'; interface Options { approvalTimesout?: boolean; approvalFails?: boolean; @@ -138,27 +138,9 @@ describe('org:login:device', () => { await prepareStubs(); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore - $$.SANDBOX.stub(Login.prototype, 'askForHiddenResponse').returns(Promise.resolve('1234')); + $$.SANDBOX.stub(common, 'clientSecretPrompt').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 bcb94b9a..6de99378 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 } from '@salesforce/ts-sinon'; -import { SfCommand } from '@salesforce/sf-plugins-core'; import LoginSfdxUrl from '../../../../src/commands/org/login/sfdx-url.js'; interface Options { @@ -186,31 +185,4 @@ 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); - }); }); diff --git a/test/commands/org/login/login.web.test.ts b/test/commands/org/login/login.web.test.ts index c599eff7..c7e035ad 100644 --- a/test/commands/org/login/login.web.test.ts +++ b/test/commands/org/login/login.web.test.ts @@ -8,13 +8,14 @@ /* 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'; import { Env } from '@salesforce/kit'; import { SfCommand, Ux } from '@salesforce/sf-plugins-core'; import LoginWeb from '../../../../src/commands/org/login/web.js'; +import common from '../../../../src/common.js'; describe('org:login:web', () => { const $$ = new TestContext(); @@ -30,8 +31,7 @@ describe('org:login:web', () => { clientSecret = '' ): Promise { authFields = await testData.getConfig(); - // @ts-ignore - $$.SANDBOX.stub(LoginWeb.prototype, 'askForClientSecret').resolves(clientSecret); + $$.SANDBOX.stub(common, 'clientSecretPrompt').resolves(clientSecret); $$.SANDBOX.stub(SfCommand.prototype, 'confirm').resolves(promptAnswer); authInfoStub = stubInterface($$.SANDBOX, { @@ -116,20 +116,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/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/yarn.lock b/yarn.lock index ecb9e39c..13563c31 100644 --- a/yarn.lock +++ b/yarn.lock @@ -445,6 +445,59 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz#e5211452df060fa8522b55c7b3c0c4d1981cb044" integrity sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw== +"@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/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" @@ -1247,6 +1300,13 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.6.tgz#818551d39113081048bdddbef96701b4e8bb9d1b" integrity sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg== +"@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@^18": version "18.18.8" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.18.8.tgz#2b285361f2357c8c8578ec86b5d097c7f464cfd6" @@ -1264,6 +1324,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-15.14.9.tgz#bc43c990c3c9be7281868bbc7b8fdd6e2b57adfa" integrity sha512-qjd88DrCxupx/kJD5yQgZdcYKZKSIGBVDIBE1/LTGcNm3d2Np/jxojkdePDdfnBHJc5W7vSMpbJ1aB7p/Py69A== +"@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" + "@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 +1388,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" @@ -2242,6 +2314,11 @@ cli-spinners@^2.5.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.7.0.tgz#f815fd30b5f9eaac02db604c7a231ed7cb2f797a" integrity sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw== +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" resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.11.tgz#ac69cdecbe81dccdba4889b9a18b7da312a9d3ee" @@ -2254,6 +2331,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" @@ -3357,7 +3439,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== @@ -5406,6 +5488,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" @@ -6577,6 +6664,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" @@ -6806,7 +6898,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==