diff --git a/commands/project/upload.ts b/commands/project/upload.ts index a67293d0e..29b349e32 100644 --- a/commands/project/upload.ts +++ b/commands/project/upload.ts @@ -12,10 +12,10 @@ const { loadAndValidateOptions } = require('../../lib/validation'); const { ensureProjectExists, getProjectConfig, - handleProjectUpload, logFeedbackMessage, validateProjectConfig, } = require('../../lib/projects'); +const { handleProjectUpload } = require('../../lib/projects/upload'); const { displayWarnLogs, pollProjectBuildAndDeploy, diff --git a/commands/project/watch.ts b/commands/project/watch.ts index d2ab74e68..96c218303 100644 --- a/commands/project/watch.ts +++ b/commands/project/watch.ts @@ -14,10 +14,10 @@ const { uiBetaTag } = require('../../lib/ui'); const { ensureProjectExists, getProjectConfig, - handleProjectUpload, validateProjectConfig, logFeedbackMessage, } = require('../../lib/projects'); +const { handleProjectUpload } = require('../../lib/projects/upload'); const { pollBuildStatus, pollDeployStatus, diff --git a/lang/en.lyaml b/lang/en.lyaml index c1d8cdd95..ee6bbdbcf 100644 --- a/lang/en.lyaml +++ b/lang/en.lyaml @@ -1094,16 +1094,6 @@ en: checkIfParentAccountIsAuthed: notAuthedError: "To develop this project locally, run {{ authCommand }} to authenticate the App Developer Account {{ accountId }} associated with {{ accountIdentifier }}." projects: - uploadProjectFiles: - add: "Uploading {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}" - fail: "Failed to upload {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}" - succeed: "Uploaded {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}" - buildCreated: "Project \"{{ projectName }}\" uploaded and build #{{ buildId }} created" - handleProjectUpload: - emptySource: "Source directory \"{{ srcDir }}\" is empty. Add files to your project and rerun `{{#yellow}}hs project upload{{/yellow}}` to upload them to HubSpot." - compressed: "Project files compressed: {{ byteCount }} bytes" - compressing: "Compressing build files to \"{{ path }}\"" - fileFiltered: "Ignore rule triggered for \"{{ filename }}\"" validateProjectConfig: configNotFound: "Unable to locate a project configuration file. Try running again from a project directory, or run {{ createCommand }} to create a new project." configMissingFields: "The project configuruation file is missing required fields." @@ -1132,6 +1122,17 @@ en: buildSucceededAutomaticallyDeploying: "Build #{{ buildId }} succeeded. {{#bold}}Automatically deploying{{/bold}} to {{ accountIdentifier }}\n" cleanedUpTempFile: "Cleaned up temporary file {{ path }}" viewDeploys: "View all deploys for this project in HubSpot" + projectUpload: + uploadProjectFiles: + add: "Uploading {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}" + fail: "Failed to upload {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}" + succeed: "Uploaded {{#bold}}{{ projectName }}{{/bold}} project files to {{ accountIdentifier }}" + buildCreated: "Project \"{{ projectName }}\" uploaded and build #{{ buildId }} created" + handleProjectUpload: + emptySource: "Source directory \"{{ srcDir }}\" is empty. Add files to your project and rerun `{{#yellow}}hs project upload{{/yellow}}` to upload them to HubSpot." + compressed: "Project files compressed: {{ byteCount }} bytes" + compressing: "Compressing build files to \"{{ path }}\"" + fileFiltered: "Ignore rule triggered for \"{{ filename }}\"" ui: betaTag: "{{#bold}}[BETA]{{/bold}}" betaWarning: diff --git a/lib/localDev.ts b/lib/localDev.ts index d24c188c6..0f9d7ebd2 100644 --- a/lib/localDev.ts +++ b/lib/localDev.ts @@ -38,7 +38,7 @@ const { isAppDeveloperAccount, isDeveloperTestAccount, } = require('./accountTypes'); -const { handleProjectUpload } = require('./projects'); +const { handleProjectUpload } = require('./projects/upload'); const { pollProjectBuildAndDeploy } = require('./projects/buildAndDeploy'); const { PROJECT_ERROR_TYPES, diff --git a/lib/projects/buildAndDeploy.ts b/lib/projects/buildAndDeploy.ts index 99cd2265e..e4787884c 100644 --- a/lib/projects/buildAndDeploy.ts +++ b/lib/projects/buildAndDeploy.ts @@ -20,7 +20,7 @@ import { ProjectTask, ProjectSubtask, ProjectPollStatusFunctionText, -} from '../../types/projects'; +} from '../../types/Projects'; import { POLLING_DELAY, PROJECT_BUILD_TEXT, diff --git a/lib/projects/index.ts b/lib/projects/index.ts index c2b19abcb..b0ef4e7aa 100644 --- a/lib/projects/index.ts +++ b/lib/projects/index.ts @@ -1,17 +1,13 @@ import fs from 'fs-extra'; import path from 'path'; -import archiver from 'archiver'; -import tmp, { FileResult } from 'tmp'; import findup from 'findup-sync'; import { logger } from '@hubspot/local-dev-lib/logger'; import { fetchFileFromRepository } from '@hubspot/local-dev-lib/github'; import { createProject, fetchProject, - uploadProject, } from '@hubspot/local-dev-lib/api/projects'; import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index'; -import { shouldIgnoreFile } from '@hubspot/local-dev-lib/ignoreRules'; import { getCwd, getAbsoluteFilePath } from '@hubspot/local-dev-lib/path'; import { downloadGithubRepoContents } from '@hubspot/local-dev-lib/github'; import { RepoPath } from '@hubspot/local-dev-lib/types/Github'; @@ -37,7 +33,7 @@ import { ProjectAddComponentData, ProjectTemplateRepoConfig, ComponentTemplate, -} from '../../types/projects'; +} from '../../types/Projects'; const i18nKey = 'lib.projects'; @@ -324,169 +320,6 @@ export async function ensureProjectExists( } } -async function uploadProjectFiles( - accountId: number, - projectName: string, - filePath: string, - uploadMessage: string, - platformVersion: string -): Promise<{ buildId?: number; error: unknown }> { - SpinniesManager.init({}); - const accountIdentifier = uiAccountDescription(accountId); - - SpinniesManager.add('upload', { - text: i18n(`${i18nKey}.uploadProjectFiles.add`, { - accountIdentifier, - projectName, - }), - succeedColor: 'white', - }); - - let buildId: number | undefined; - let error: unknown; - - try { - const { data: upload } = await uploadProject( - accountId, - projectName, - filePath, - uploadMessage, - platformVersion - ); - - buildId = upload.buildId; - - SpinniesManager.succeed('upload', { - text: i18n(`${i18nKey}.uploadProjectFiles.succeed`, { - accountIdentifier, - projectName, - }), - }); - - logger.debug( - i18n(`${i18nKey}.uploadProjectFiles.buildCreated`, { - buildId, - projectName, - }) - ); - } catch (err) { - SpinniesManager.fail('upload', { - text: i18n(`${i18nKey}.uploadProjectFiles.fail`, { - accountIdentifier, - projectName, - }), - }); - - error = err; - } - - return { buildId, error }; -} - -type ProjectUploadCallbackFunction = ( - accountId: number, - projectConfig: ProjectConfig, - tempFile: FileResult, - buildId?: number -) => Promise; - -type ProjectUploadDefaultResult = { - uploadError?: unknown; -}; - -export async function handleProjectUpload( - accountId: number, - projectConfig: ProjectConfig, - projectDir: string, - callbackFunc: ProjectUploadCallbackFunction, - uploadMessage: string -) { - const srcDir = path.resolve(projectDir, projectConfig.srcDir); - - const filenames = fs.readdirSync(srcDir); - if (!filenames || filenames.length === 0) { - logger.log( - i18n(`${i18nKey}.handleProjectUpload.emptySource`, { - srcDir: projectConfig.srcDir, - }) - ); - process.exit(EXIT_CODES.SUCCESS); - } - - const tempFile = tmp.fileSync({ postfix: '.zip' }); - - logger.debug( - i18n(`${i18nKey}.handleProjectUpload.compressing`, { - path: tempFile.name, - }) - ); - - const output = fs.createWriteStream(tempFile.name); - const archive = archiver('zip'); - - const result = new Promise(resolve => - output.on('close', async function () { - let uploadResult: ProjectUploadDefaultResult | T | undefined; - - logger.debug( - i18n(`${i18nKey}.handleProjectUpload.compressed`, { - byteCount: archive.pointer(), - }) - ); - - const { buildId, error } = await uploadProjectFiles( - accountId, - projectConfig.name, - tempFile.name, - uploadMessage, - projectConfig.platformVersion - ); - - if (error) { - console.log(error); - uploadResult = { uploadError: error }; - } else if (callbackFunc) { - console.log('callbackfunc'); - uploadResult = await callbackFunc( - accountId, - projectConfig, - tempFile, - buildId - ); - } - resolve(uploadResult || {}); - }) - ); - - archive.pipe(output); - - let loggedIgnoredNodeModule = false; - - archive.directory(srcDir, false, file => { - const ignored = shouldIgnoreFile(file.name, true); - if (ignored) { - const isNodeModule = file.name.includes('node_modules'); - - if (!isNodeModule || !loggedIgnoredNodeModule) { - logger.debug( - i18n(`${i18nKey}.handleProjectUpload.fileFiltered`, { - filename: file.name, - }) - ); - } - - if (isNodeModule && !loggedIgnoredNodeModule) { - loggedIgnoredNodeModule = true; - } - } - return ignored ? false : file; - }); - - archive.finalize(); - - return result; -} - export function logFeedbackMessage(buildId: number): void { if (buildId > 0 && buildId % FEEDBACK_INTERVAL === 0) { uiLine(); diff --git a/lib/projects/upload.ts b/lib/projects/upload.ts new file mode 100644 index 000000000..4f4c96d44 --- /dev/null +++ b/lib/projects/upload.ts @@ -0,0 +1,177 @@ +import archiver from 'archiver'; +import tmp, { FileResult } from 'tmp'; +import fs from 'fs-extra'; +import path from 'path'; +import { uploadProject } from '@hubspot/local-dev-lib/api/projects'; +import { shouldIgnoreFile } from '@hubspot/local-dev-lib/ignoreRules'; +import { logger } from '@hubspot/local-dev-lib/logger'; + +import SpinniesManager from '../ui/SpinniesManager'; +import { uiAccountDescription } from '../ui'; +import { i18n } from '../lang'; +import { ProjectConfig } from '../../types/Projects'; +import { EXIT_CODES } from '../enums/exitCodes'; + +const i18nKey = 'lib.projectUpload'; + +async function uploadProjectFiles( + accountId: number, + projectName: string, + filePath: string, + uploadMessage: string, + platformVersion: string +): Promise<{ buildId?: number; error: unknown }> { + SpinniesManager.init({}); + const accountIdentifier = uiAccountDescription(accountId); + + SpinniesManager.add('upload', { + text: i18n(`${i18nKey}.uploadProjectFiles.add`, { + accountIdentifier, + projectName, + }), + succeedColor: 'white', + }); + + let buildId: number | undefined; + let error: unknown; + + try { + const { data: upload } = await uploadProject( + accountId, + projectName, + filePath, + uploadMessage, + platformVersion + ); + + buildId = upload.buildId; + + SpinniesManager.succeed('upload', { + text: i18n(`${i18nKey}.uploadProjectFiles.succeed`, { + accountIdentifier, + projectName, + }), + }); + + logger.debug( + i18n(`${i18nKey}.uploadProjectFiles.buildCreated`, { + buildId, + projectName, + }) + ); + } catch (err) { + SpinniesManager.fail('upload', { + text: i18n(`${i18nKey}.uploadProjectFiles.fail`, { + accountIdentifier, + projectName, + }), + }); + + error = err; + } + + return { buildId, error }; +} + +type ProjectUploadCallbackFunction = ( + accountId: number, + projectConfig: ProjectConfig, + tempFile: FileResult, + buildId?: number +) => Promise; + +type ProjectUploadDefaultResult = { + uploadError?: unknown; +}; + +export async function handleProjectUpload( + accountId: number, + projectConfig: ProjectConfig, + projectDir: string, + callbackFunc: ProjectUploadCallbackFunction, + uploadMessage: string +) { + const srcDir = path.resolve(projectDir, projectConfig.srcDir); + + const filenames = fs.readdirSync(srcDir); + if (!filenames || filenames.length === 0) { + logger.log( + i18n(`${i18nKey}.handleProjectUpload.emptySource`, { + srcDir: projectConfig.srcDir, + }) + ); + process.exit(EXIT_CODES.SUCCESS); + } + + const tempFile = tmp.fileSync({ postfix: '.zip' }); + + logger.debug( + i18n(`${i18nKey}.handleProjectUpload.compressing`, { + path: tempFile.name, + }) + ); + + const output = fs.createWriteStream(tempFile.name); + const archive = archiver('zip'); + + const result = new Promise(resolve => + output.on('close', async function () { + let uploadResult: ProjectUploadDefaultResult | T | undefined; + + logger.debug( + i18n(`${i18nKey}.handleProjectUpload.compressed`, { + byteCount: archive.pointer(), + }) + ); + + const { buildId, error } = await uploadProjectFiles( + accountId, + projectConfig.name, + tempFile.name, + uploadMessage, + projectConfig.platformVersion + ); + + if (error) { + console.log(error); + uploadResult = { uploadError: error }; + } else if (callbackFunc) { + uploadResult = await callbackFunc( + accountId, + projectConfig, + tempFile, + buildId + ); + } + resolve(uploadResult || {}); + }) + ); + + archive.pipe(output); + + let loggedIgnoredNodeModule = false; + + archive.directory(srcDir, false, file => { + const ignored = shouldIgnoreFile(file.name, true); + if (ignored) { + const isNodeModule = file.name.includes('node_modules'); + + if (!isNodeModule || !loggedIgnoredNodeModule) { + logger.debug( + i18n(`${i18nKey}.handleProjectUpload.fileFiltered`, { + filename: file.name, + }) + ); + } + + if (isNodeModule && !loggedIgnoredNodeModule) { + loggedIgnoredNodeModule = true; + } + } + return ignored ? false : file; + }); + + archive.finalize(); + + return result; +} diff --git a/lib/prompts/accountNamePrompt.ts b/lib/prompts/accountNamePrompt.ts index 4efaf6c59..4ca2bf86b 100644 --- a/lib/prompts/accountNamePrompt.ts +++ b/lib/prompts/accountNamePrompt.ts @@ -1,7 +1,7 @@ import { accountNameExistsInConfig } from '@hubspot/local-dev-lib/config'; import { promptUser } from './promptUtils'; import { i18n } from '../lang'; -import { PromptConfig } from '../../types/prompts'; +import { PromptConfig } from '../../types/Prompts'; import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config'; import { AccountType } from '@hubspot/local-dev-lib/types/Accounts'; diff --git a/lib/prompts/accountsPrompt.ts b/lib/prompts/accountsPrompt.ts index 58f4c8e26..bee5ce10a 100644 --- a/lib/prompts/accountsPrompt.ts +++ b/lib/prompts/accountsPrompt.ts @@ -7,7 +7,7 @@ import { promptUser } from './promptUtils'; import { i18n } from '../lang'; import { uiAccountDescription } from '../ui'; import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts'; -import { PromptChoices } from '../../types/prompts'; +import { PromptChoices } from '../../types/Prompts'; function mapAccountChoices( portals: CLIAccount[] | null | undefined diff --git a/lib/prompts/createApiSamplePrompt.ts b/lib/prompts/createApiSamplePrompt.ts index d9ab223ba..c8d78b6ef 100644 --- a/lib/prompts/createApiSamplePrompt.ts +++ b/lib/prompts/createApiSamplePrompt.ts @@ -1,6 +1,6 @@ import { promptUser } from './promptUtils'; import { i18n } from '../lang'; -import { PromptConfig } from '../../types/prompts'; +import { PromptConfig } from '../../types/Prompts'; const i18nKey = 'lib.prompts.createApiSamplePrompt'; @@ -37,8 +37,8 @@ function getSampleTypesPrompt( name: `${choice.name} - ${choice.description}`, value: choice.id, })), - validate: function(input?: string) { - return new Promise(function(resolve, reject) { + validate: function (input?: string) { + return new Promise(function (resolve, reject) { if (input && input.length > 0) { resolve(true); } else { @@ -60,8 +60,8 @@ function getLanguagesPrompt( name: choice, value: choice, })), - validate: function(input: string | undefined) { - return new Promise(function(resolve, reject) { + validate: function (input: string | undefined) { + return new Promise(function (resolve, reject) { if (input && input.length > 0) { resolve(true); } diff --git a/lib/prompts/createFunctionPrompt.ts b/lib/prompts/createFunctionPrompt.ts index 197fdf8ba..0ec6f1f46 100644 --- a/lib/prompts/createFunctionPrompt.ts +++ b/lib/prompts/createFunctionPrompt.ts @@ -1,6 +1,6 @@ import { promptUser } from './promptUtils'; import { i18n } from '../lang'; -import { PromptConfig } from '../../types/prompts'; +import { PromptConfig } from '../../types/Prompts'; const i18nKey = 'lib.prompts.createFunctionPrompt'; diff --git a/lib/prompts/createModulePrompt.ts b/lib/prompts/createModulePrompt.ts index c7b90d1ee..bd4e1cf3d 100644 --- a/lib/prompts/createModulePrompt.ts +++ b/lib/prompts/createModulePrompt.ts @@ -1,4 +1,4 @@ -import { PromptConfig } from '../../types/prompts'; +import { PromptConfig } from '../../types/Prompts'; import { promptUser } from './promptUtils'; import { i18n } from '../lang'; @@ -53,7 +53,7 @@ const CONTENT_TYPES_PROMPT: PromptConfig = { { name: 'Membership', value: 'MEMBERSHIP' }, ], validate: (input: string[]) => { - return new Promise(function(resolve, reject) { + return new Promise(function (resolve, reject) { if (input.length > 0) { resolve(true); } diff --git a/lib/prompts/createProjectPrompt.ts b/lib/prompts/createProjectPrompt.ts index 48647f59d..3bc4d4ad4 100644 --- a/lib/prompts/createProjectPrompt.ts +++ b/lib/prompts/createProjectPrompt.ts @@ -20,7 +20,7 @@ import { RepoPath } from '@hubspot/local-dev-lib/types/Github'; import { ProjectTemplate, ProjectTemplateRepoConfig, -} from '../../types/projects'; +} from '../../types/Projects'; const i18nKey = 'lib.prompts.createProjectPrompt'; diff --git a/lib/prompts/createTemplatePrompt.ts b/lib/prompts/createTemplatePrompt.ts index ecfae6da1..7aa0b1a41 100644 --- a/lib/prompts/createTemplatePrompt.ts +++ b/lib/prompts/createTemplatePrompt.ts @@ -1,6 +1,6 @@ import { promptUser } from './promptUtils'; import { i18n } from '../lang'; -import { PromptChoices, PromptConfig } from '../../types/prompts'; +import { PromptChoices, PromptConfig } from '../../types/Prompts'; const i18nKey = 'lib.prompts.createTemplatePrompt'; @@ -15,7 +15,7 @@ const templateTypeChoices = [ ] satisfies PromptChoices; interface CreateTemplatePromptResponse { - templateType: typeof templateTypeChoices[number]['value']; + templateType: (typeof templateTypeChoices)[number]['value']; } const TEMPLATE_TYPE_PROMPT: PromptConfig = { diff --git a/lib/prompts/personalAccessKeyPrompt.ts b/lib/prompts/personalAccessKeyPrompt.ts index 7762868ef..dd15dc6ef 100644 --- a/lib/prompts/personalAccessKeyPrompt.ts +++ b/lib/prompts/personalAccessKeyPrompt.ts @@ -11,7 +11,7 @@ import { getCliAccountNamePromptConfig } from './accountNamePrompt'; import { i18n } from '../lang'; import { uiInfoSection } from '../ui'; import { EXIT_CODES } from '../enums/exitCodes'; -import { PromptConfig } from '../../types/prompts'; +import { PromptConfig } from '../../types/Prompts'; const i18nKey = 'lib.prompts.personalAccessKeyPrompt'; @@ -60,9 +60,10 @@ export async function personalAccessKeyPrompt({ if (account) { url = `${websiteOrigin}/personal-access-key/${account}`; } - const { personalAcessKeyBrowserOpenPrep: shouldOpen } = await promptUser< - PersonalAccessKeyBrowserOpenPrepResponse - >([PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP]); + const { personalAcessKeyBrowserOpenPrep: shouldOpen } = + await promptUser([ + PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP, + ]); if (shouldOpen) { open(url, { url: true }); } else { @@ -72,9 +73,8 @@ export async function personalAccessKeyPrompt({ } logger.log(i18n(`${i18nKey}.logs.openingWebBrowser`, { url })); - const { personalAccessKey } = await promptUser< - PersonalAccessKeyPromptResponse - >(PERSONAL_ACCESS_KEY); + const { personalAccessKey } = + await promptUser(PERSONAL_ACCESS_KEY); return { personalAccessKey, @@ -122,11 +122,12 @@ const CLIENT_SECRET: PromptConfig = { }, }; -const PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP: PromptConfig = { - name: 'personalAcessKeyBrowserOpenPrep', - type: 'confirm', - message: i18n(`${i18nKey}.personalAccessKeyBrowserOpenPrompt`), -}; +const PERSONAL_ACCESS_KEY_BROWSER_OPEN_PREP: PromptConfig = + { + name: 'personalAcessKeyBrowserOpenPrep', + type: 'confirm', + message: i18n(`${i18nKey}.personalAccessKeyBrowserOpenPrompt`), + }; const PERSONAL_ACCESS_KEY: PromptConfig = { name: 'personalAccessKey', diff --git a/lib/prompts/projectAddPrompt.ts b/lib/prompts/projectAddPrompt.ts index 6a8ca7580..097f935f2 100644 --- a/lib/prompts/projectAddPrompt.ts +++ b/lib/prompts/projectAddPrompt.ts @@ -1,6 +1,6 @@ import { promptUser } from './promptUtils'; import { i18n } from '../lang'; -import { ProjectAddComponentData } from '../../types/projects'; +import { ProjectAddComponentData } from '../../types/Projects'; const i18nKey = 'lib.prompts.projectAddPrompt'; diff --git a/lib/prompts/projectDevTargetAccountPrompt.ts b/lib/prompts/projectDevTargetAccountPrompt.ts index ad56fdf58..8be678aa2 100644 --- a/lib/prompts/projectDevTargetAccountPrompt.ts +++ b/lib/prompts/projectDevTargetAccountPrompt.ts @@ -17,14 +17,12 @@ import { DeveloperTestAccount, FetchDeveloperTestAccountsResponse, } from '@hubspot/local-dev-lib/types/developerTestAccounts'; -import { PromptChoices } from '../../types/prompts'; +import { PromptChoices } from '../../types/Prompts'; import { EXIT_CODES } from '../enums/exitCodes'; const i18nKey = 'lib.prompts.projectDevTargetAccountPrompt'; -function mapNestedAccount( - accountConfig: CLIAccount -): { +function mapNestedAccount(accountConfig: CLIAccount): { name: string; value: { targetAccountId: number | null; diff --git a/lib/prompts/promptUtils.ts b/lib/prompts/promptUtils.ts index 8f8abec7b..c1b1d10c8 100644 --- a/lib/prompts/promptUtils.ts +++ b/lib/prompts/promptUtils.ts @@ -8,7 +8,7 @@ import { GenericPromptResponse, PromptWhen, PromptChoices, -} from '../../types/prompts'; +} from '../../types/Prompts'; const promptModule = inquirer.createPromptModule(); diff --git a/lib/prompts/sandboxesPrompt.ts b/lib/prompts/sandboxesPrompt.ts index 1046875a8..5a8b4e983 100644 --- a/lib/prompts/sandboxesPrompt.ts +++ b/lib/prompts/sandboxesPrompt.ts @@ -9,7 +9,7 @@ import { getConfigAccounts, } from '@hubspot/local-dev-lib/config'; import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts'; -import { PromptChoices } from '../../types/prompts'; +import { PromptChoices } from '../../types/Prompts'; const i18nKey = 'lib.prompts.sandboxesPrompt';