@hubspot/cli 7.7.31-experimental.0 → 7.7.33-experimental.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/commands/app.js +1 -6
  2. package/commands/getStarted.js +5 -4
  3. package/commands/project/__tests__/add.test.js +3 -5
  4. package/commands/project/__tests__/deploy.test.js +3 -2
  5. package/commands/project/add.js +2 -4
  6. package/commands/project/deploy.js +9 -61
  7. package/commands/project/dev/index.js +1 -1
  8. package/commands/project/dev/unifiedFlow.js +3 -0
  9. package/commands/project/upload.d.ts +2 -2
  10. package/commands/project/upload.js +3 -3
  11. package/commands/project/validate.js +1 -1
  12. package/commands/project/watch.js +2 -2
  13. package/commands/testAccount/create.js +0 -3
  14. package/lang/en.d.ts +8 -26
  15. package/lang/en.js +9 -27
  16. package/lib/__tests__/hasFeature.test.js +145 -7
  17. package/lib/__tests__/importData.test.js +1 -1
  18. package/lib/app/migrate.js +9 -2
  19. package/lib/constants.d.ts +2 -0
  20. package/lib/constants.js +2 -0
  21. package/lib/errorHandlers/index.d.ts +4 -0
  22. package/lib/errorHandlers/index.js +1 -1
  23. package/lib/hasFeature.js +6 -0
  24. package/lib/importData.js +1 -1
  25. package/lib/mcp/setup.js +1 -1
  26. package/lib/projectProfiles.d.ts +1 -1
  27. package/lib/projectProfiles.js +2 -10
  28. package/lib/projects/__tests__/AppDevModeInterface.test.js +61 -44
  29. package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
  30. package/lib/projects/__tests__/deploy.test.js +164 -0
  31. package/lib/projects/__tests__/{buildAndDeploy.test.js → platformVersion.test.js} +2 -2
  32. package/lib/projects/add/__tests__/legacyAddComponent.test.js +49 -6
  33. package/lib/projects/add/__tests__/v3AddComponent.test.js +71 -1
  34. package/lib/projects/add/legacyAddComponent.d.ts +1 -1
  35. package/lib/projects/add/legacyAddComponent.js +5 -1
  36. package/lib/projects/add/v3AddComponent.d.ts +1 -0
  37. package/lib/projects/add/v3AddComponent.js +2 -2
  38. package/lib/projects/create/__tests__/v3.test.js +97 -9
  39. package/lib/projects/create/index.js +2 -2
  40. package/lib/projects/create/legacy.js +1 -1
  41. package/lib/projects/create/v3.d.ts +2 -2
  42. package/lib/projects/create/v3.js +35 -12
  43. package/lib/projects/deploy.d.ts +13 -0
  44. package/lib/projects/deploy.js +63 -0
  45. package/lib/projects/localDev/AppDevModeInterface.d.ts +0 -2
  46. package/lib/projects/localDev/AppDevModeInterface.js +65 -36
  47. package/lib/projects/localDev/DevServerManagerV2.js +1 -0
  48. package/lib/projects/localDev/LocalDevProcess.js +3 -1
  49. package/lib/projects/localDev/LocalDevState.d.ts +5 -2
  50. package/lib/projects/localDev/LocalDevState.js +9 -1
  51. package/lib/projects/localDev/helpers/project.js +1 -1
  52. package/lib/projects/platformVersion.d.ts +1 -0
  53. package/lib/projects/platformVersion.js +10 -0
  54. package/lib/projects/{buildAndDeploy.d.ts → pollProjectBuildAndDeploy.d.ts} +0 -1
  55. package/lib/projects/{buildAndDeploy.js → pollProjectBuildAndDeploy.js} +0 -10
  56. package/lib/projects/structure.d.ts +2 -2
  57. package/lib/projects/upload.d.ts +1 -2
  58. package/lib/projects/upload.js +1 -2
  59. package/lib/projects/urls.d.ts +1 -0
  60. package/lib/projects/urls.js +3 -0
  61. package/lib/prompts/__tests__/projectAddPrompt.test.d.ts +1 -0
  62. package/lib/prompts/__tests__/projectAddPrompt.test.js +143 -0
  63. package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.d.ts +1 -0
  64. package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.js +160 -0
  65. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +1 -0
  66. package/lib/prompts/importDataFilePathPrompt.js +4 -2
  67. package/lib/prompts/installAppPrompt.d.ts +6 -1
  68. package/lib/prompts/installAppPrompt.js +6 -1
  69. package/lib/prompts/projectAddPrompt.js +1 -1
  70. package/lib/prompts/selectProjectTemplatePrompt.js +1 -1
  71. package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +32 -0
  72. package/mcp-server/tools/cms/HsCreateFunctionTool.js +96 -0
  73. package/mcp-server/tools/cms/HsCreateTemplateTool.d.ts +26 -0
  74. package/mcp-server/tools/cms/HsCreateTemplateTool.js +75 -0
  75. package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +32 -0
  76. package/mcp-server/tools/cms/HsFunctionLogsTool.js +76 -0
  77. package/mcp-server/tools/cms/HsListFunctionsTool.d.ts +23 -0
  78. package/mcp-server/tools/cms/HsListFunctionsTool.js +58 -0
  79. package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.d.ts +1 -0
  80. package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +251 -0
  81. package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.d.ts +1 -0
  82. package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +206 -0
  83. package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.d.ts +1 -0
  84. package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +183 -0
  85. package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.d.ts +1 -0
  86. package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +120 -0
  87. package/mcp-server/tools/index.js +8 -0
  88. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -3
  89. package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
  90. package/mcp-server/tools/project/GetConfigValuesTool.js +3 -3
  91. package/mcp-server/tools/project/constants.d.ts +1 -1
  92. package/mcp-server/tools/project/constants.js +6 -4
  93. package/package.json +4 -3
  94. package/types/LocalDev.d.ts +2 -1
  95. package/types/Projects.d.ts +1 -0
  96. package/types/Yargs.d.ts +1 -1
  97. package/ui/components/BoxWithTitle.d.ts +8 -0
  98. package/ui/components/BoxWithTitle.js +9 -0
  99. package/ui/components/HorizontalSelectPrompt.d.ts +8 -0
  100. package/ui/components/HorizontalSelectPrompt.js +30 -0
  101. package/ui/components/StatusMessageBoxes.d.ts +12 -0
  102. package/ui/components/StatusMessageBoxes.js +31 -0
  103. package/ui/lib/ui-testing-utils.d.ts +9 -0
  104. package/ui/lib/ui-testing-utils.js +47 -0
  105. package/ui/lib/useTerminalSize.d.ts +13 -0
  106. package/ui/lib/useTerminalSize.js +31 -0
  107. package/ui/styles.d.ts +18 -0
  108. package/ui/styles.js +18 -0
  109. package/ui/views/UiSandbox.d.ts +5 -0
  110. package/ui/views/UiSandbox.js +25 -0
  111. package/commands/app/__tests__/install.test.js +0 -47
  112. package/commands/app/install.d.ts +0 -8
  113. package/commands/app/install.js +0 -122
  114. /package/{commands/app/__tests__/install.test.d.ts → lib/projects/__tests__/deploy.test.d.ts} +0 -0
  115. /package/lib/projects/__tests__/{buildAndDeploy.test.d.ts → platformVersion.test.d.ts} +0 -0
package/commands/app.js CHANGED
@@ -1,16 +1,11 @@
1
1
  import migrateCommand from './app/migrate.js';
2
2
  import appSecretCommand from './app/secret.js';
3
- import installAppCommand from './app/install.js';
4
3
  import { makeYargsBuilder } from '../lib/yargsUtils.js';
5
4
  const command = ['app', 'apps'];
6
5
  // Keep the command hidden for now
7
6
  const describe = undefined;
8
7
  function appBuilder(yargs) {
9
- yargs
10
- .command(migrateCommand)
11
- .command(appSecretCommand)
12
- .command(installAppCommand)
13
- .demandCommand(1, '');
8
+ yargs.command(migrateCommand).command(appSecretCommand).demandCommand(1, '');
14
9
  return yargs;
15
10
  }
16
11
  const builder = makeYargsBuilder(appBuilder, command, describe);
@@ -16,7 +16,8 @@ import { handleProjectUpload } from '../lib/projects/upload.js';
16
16
  import { PROJECT_CONFIG_FILE, GET_STARTED_OPTIONS, HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, } from '../lib/constants.js';
17
17
  import { writeProjectConfig, getProjectConfig, validateProjectConfig, } from '../lib/projects/config.js';
18
18
  import { getProjectPackageJsonLocations, installPackages, } from '../lib/dependencyManagement.js';
19
- import { pollProjectBuildAndDeploy, useV3Api, } from '../lib/projects/buildAndDeploy.js';
19
+ import { pollProjectBuildAndDeploy } from '../lib/projects/pollProjectBuildAndDeploy.js';
20
+ import { useV3Api } from '../lib/projects/platformVersion.js';
20
21
  import { openLink } from '../lib/links.js';
21
22
  import { getStaticAuthAppInstallUrl } from '../lib/app/urls.js';
22
23
  import { getEnv } from '@hubspot/local-dev-lib/config';
@@ -28,10 +29,12 @@ async function handler(args) {
28
29
  const { derivedAccountId } = args;
29
30
  const env = getEnv(derivedAccountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD;
30
31
  await trackCommandUsage('get-started', {}, derivedAccountId);
32
+ const accountName = uiAccountDescription(derivedAccountId);
31
33
  // TODO: Put this in constants.ts once we have a defined place for the template before INBOUND
32
34
  const templateSource = 'robrown-hubspot/hubspot-project-components-ua-app-objects-beta';
33
35
  uiInfoSection(commands.getStarted.startTitle, () => {
34
36
  uiLogger.log(commands.getStarted.startDescription);
37
+ uiLogger.log(commands.getStarted.guideOverview(accountName));
35
38
  });
36
39
  const { default: selectedOption } = await promptUser([
37
40
  {
@@ -163,7 +166,6 @@ async function handler(args) {
163
166
  uiLogger.log(' ');
164
167
  }
165
168
  // 6. Ask user if they want to upload the project
166
- const accountName = uiAccountDescription(derivedAccountId);
167
169
  const { shouldUpload } = await promptUser([
168
170
  {
169
171
  type: 'confirm',
@@ -192,12 +194,11 @@ async function handler(args) {
192
194
  process.exit(EXIT_CODES.ERROR);
193
195
  }
194
196
  validateProjectConfig(newProjectConfig, newProjectDir);
195
- const targetAccountId = derivedAccountId;
196
197
  uiLogger.log(' ');
197
198
  uiLogger.log(commands.getStarted.logs.uploadingProject);
198
199
  uiLogger.log(' ');
199
200
  const { result, uploadError } = await handleProjectUpload({
200
- accountId: targetAccountId,
201
+ accountId: derivedAccountId,
201
202
  projectConfig: newProjectConfig,
202
203
  projectDir: newProjectDir,
203
204
  callbackFunc: pollProjectBuildAndDeploy,
@@ -4,13 +4,13 @@ import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, } from
4
4
  import { v3AddComponent } from '../../../lib/projects/add/v3AddComponent.js';
5
5
  import { legacyAddComponent } from '../../../lib/projects/add/legacyAddComponent.js';
6
6
  import { getProjectConfig } from '../../../lib/projects/config.js';
7
- import { useV3Api } from '../../../lib/projects/buildAndDeploy.js';
7
+ import { useV3Api } from '../../../lib/projects/platformVersion.js';
8
8
  import { trackCommandUsage } from '../../../lib/usageTracking.js';
9
9
  vi.mock('../../../lib/commonOpts');
10
10
  vi.mock('../../../lib/projects/add/v3AddComponent');
11
11
  vi.mock('../../../lib/projects/add/legacyAddComponent');
12
12
  vi.mock('../../../lib/projects/config');
13
- vi.mock('../../../lib/projects/buildAndDeploy');
13
+ vi.mock('../../../lib/projects/platformVersion');
14
14
  vi.mock('../../../lib/usageTracking');
15
15
  const mockedV3AddComponent = vi.mocked(v3AddComponent);
16
16
  const mockedLegacyAddComponent = vi.mocked(legacyAddComponent);
@@ -82,15 +82,13 @@ describe('commands/project/add', () => {
82
82
  it('should call v3AddComponent with accountId for v3 projects', async () => {
83
83
  mockedUseV3Api.mockReturnValue(true);
84
84
  await expect(projectAddCommand.handler(mockArgs)).rejects.toThrow('process.exit called');
85
- expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', undefined, 123);
86
85
  expect(mockedV3AddComponent).toHaveBeenCalledWith(mockArgs, mockProjectDir, mockProjectConfig, 123);
87
86
  expect(mockedLegacyAddComponent).not.toHaveBeenCalled();
88
87
  });
89
88
  it('should call legacyAddComponent for non-v3 projects', async () => {
90
89
  mockedUseV3Api.mockReturnValue(false);
91
90
  await expect(projectAddCommand.handler(mockArgs)).rejects.toThrow('process.exit called');
92
- expect(mockedTrackCommandUsage).toHaveBeenCalledWith('project-add', undefined, 123);
93
- expect(mockedLegacyAddComponent).toHaveBeenCalledWith(mockArgs, mockProjectDir, mockProjectConfig);
91
+ expect(mockedLegacyAddComponent).toHaveBeenCalledWith(mockArgs, mockProjectDir, mockProjectConfig, 123);
94
92
  expect(mockedV3AddComponent).not.toHaveBeenCalled();
95
93
  });
96
94
  it('should exit with error when project config is not found', async () => {
@@ -8,7 +8,7 @@ import * as ui from '../../../lib/ui/index.js';
8
8
  import { addAccountOptions, addConfigOptions, addJSONOutputOptions, addUseEnvironmentOptions, } from '../../../lib/commonOpts.js';
9
9
  import * as projectUtils from '../../../lib/projects/config.js';
10
10
  import * as projectUrlUtils from '../../../lib/projects/urls.js';
11
- import { pollDeployStatus } from '../../../lib/projects/buildAndDeploy.js';
11
+ import { pollDeployStatus } from '../../../lib/projects/pollProjectBuildAndDeploy.js';
12
12
  import * as projectNamePrompt from '../../../lib/prompts/projectNamePrompt.js';
13
13
  import * as promptUtils from '../../../lib/prompts/promptUtils.js';
14
14
  import { trackCommandUsage } from '../../../lib/usageTracking.js';
@@ -23,7 +23,8 @@ vi.mock('../../../lib/commonOpts');
23
23
  vi.mock('../../../lib/validation');
24
24
  vi.mock('../../../lib/projects/config');
25
25
  vi.mock('../../../lib/projects/urls');
26
- vi.mock('../../../lib/projects/buildAndDeploy');
26
+ vi.mock('../../../lib/projects/pollProjectBuildAndDeploy');
27
+ vi.mock('../../../lib/projects/platformVersion');
27
28
  vi.mock('../../../lib/prompts/projectNamePrompt');
28
29
  vi.mock('../../../lib/prompts/promptUtils');
29
30
  vi.mock('../../../lib/usageTracking');
@@ -1,11 +1,10 @@
1
1
  import { logError } from '../../lib/errorHandlers/index.js';
2
- import { trackCommandUsage } from '../../lib/usageTracking.js';
3
2
  import { getProjectConfig } from '../../lib/projects/config.js';
4
3
  import { uiBetaTag } from '../../lib/ui/index.js';
5
4
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
6
5
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
7
6
  import { commands } from '../../lang/en.js';
8
- import { useV3Api } from '../../lib/projects/buildAndDeploy.js';
7
+ import { useV3Api } from '../../lib/projects/platformVersion.js';
9
8
  import { legacyAddComponent } from '../../lib/projects/add/legacyAddComponent.js';
10
9
  import { v3AddComponent } from '../../lib/projects/add/v3AddComponent.js';
11
10
  import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, } from '../../lib/constants.js';
@@ -15,7 +14,6 @@ const describe = uiBetaTag(commands.project.add.describe, false);
15
14
  async function handler(args) {
16
15
  try {
17
16
  const { derivedAccountId } = args;
18
- trackCommandUsage('project-add', undefined, derivedAccountId);
19
17
  const { projectConfig, projectDir } = await getProjectConfig();
20
18
  if (!projectDir || !projectConfig) {
21
19
  uiLogger.error(commands.project.add.error.locationInProject);
@@ -26,7 +24,7 @@ async function handler(args) {
26
24
  await v3AddComponent(args, projectDir, projectConfig, derivedAccountId);
27
25
  }
28
26
  else {
29
- await legacyAddComponent(args, projectDir, projectConfig);
27
+ await legacyAddComponent(args, projectDir, projectConfig, derivedAccountId);
30
28
  }
31
29
  }
32
30
  catch (e) {
@@ -1,11 +1,10 @@
1
- import { deployProject, fetchProject, } from '@hubspot/local-dev-lib/api/projects';
1
+ import { fetchProject } from '@hubspot/local-dev-lib/api/projects';
2
2
  import { getAccountConfig } from '@hubspot/local-dev-lib/config';
3
3
  import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
4
- import { useV3Api } from '../../lib/projects/buildAndDeploy.js';
4
+ import { useV3Api } from '../../lib/projects/platformVersion.js';
5
5
  import { trackCommandUsage } from '../../lib/usageTracking.js';
6
6
  import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
7
7
  import { getProjectConfig } from '../../lib/projects/config.js';
8
- import { pollDeployStatus } from '../../lib/projects/buildAndDeploy.js';
9
8
  import { projectNamePrompt } from '../../lib/prompts/projectNamePrompt.js';
10
9
  import { promptUser } from '../../lib/prompts/promptUtils.js';
11
10
  import { uiBetaTag, uiLine } from '../../lib/ui/index.js';
@@ -13,54 +12,11 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
13
12
  import { uiLogger } from '../../lib/ui/logger.js';
14
13
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
15
14
  import { loadProfile, logProfileFooter, logProfileHeader, exitIfUsingProfiles, } from '../../lib/projectProfiles.js';
16
- import { PROJECT_ERROR_TYPES, PROJECT_DEPLOY_TEXT, } from '../../lib/constants.js';
15
+ import { PROJECT_DEPLOY_TEXT } from '../../lib/constants.js';
17
16
  import { commands } from '../../lang/en.js';
17
+ import { handleProjectDeploy, validateBuildIdForDeploy, logDeployErrors, } from '../../lib/projects/deploy.js';
18
18
  const command = 'deploy';
19
19
  const describe = uiBetaTag(commands.project.deploy.describe, false);
20
- function validateBuildId(buildId, deployedBuildId, latestBuildId, projectName, accountId) {
21
- if (Number(buildId) > latestBuildId) {
22
- return commands.project.deploy.errors.buildIdDoesNotExist(accountId, buildId, projectName);
23
- }
24
- if (Number(buildId) === deployedBuildId) {
25
- return commands.project.deploy.errors.buildAlreadyDeployed(accountId, buildId, projectName);
26
- }
27
- return true;
28
- }
29
- function logDeployErrors(errorData) {
30
- uiLogger.error(errorData.message);
31
- errorData.errors.forEach(err => {
32
- // This is how the pre-deploy check manifests itself in < 2025.2 projects
33
- if (err.subCategory === PROJECT_ERROR_TYPES.DEPLOY_CONTAINS_REMOVALS) {
34
- uiLogger.log(commands.project.deploy.errors.deployContainsRemovals(err.context.COMPONENT_NAME));
35
- }
36
- else {
37
- uiLogger.log(err.message);
38
- }
39
- });
40
- }
41
- function handleBlockedDeploy(deployResp) {
42
- const deployCanBeForced = deployResp.issues.every(issue => issue.blockingMessages.every(message => message.isWarning));
43
- uiLogger.log('');
44
- if (deployCanBeForced) {
45
- uiLogger.warn(commands.project.deploy.errors.deployWarningsHeader);
46
- uiLogger.log('');
47
- }
48
- else {
49
- uiLogger.error(commands.project.deploy.errors.deployBlockedHeader);
50
- uiLogger.log('');
51
- }
52
- deployResp.issues.forEach(issue => {
53
- if (issue.blockingMessages.length > 0) {
54
- issue.blockingMessages.forEach(message => {
55
- uiLogger.log(commands.project.deploy.errors.deployIssueComponentWarning(issue.uid, issue.componentTypeName, message.message));
56
- });
57
- }
58
- else {
59
- uiLogger.log(commands.project.deploy.errors.deployIssueComponentGeneric(issue.uid, issue.componentTypeName));
60
- }
61
- uiLogger.log('');
62
- });
63
- }
64
20
  async function handler(args) {
65
21
  const { derivedAccountId, project: projectOption, buildId: buildIdOption, force: forceOption, deployLatestBuild: deployLatestBuildOption, json: formatOutputAsJson, } = args;
66
22
  const accountConfig = getAccountConfig(derivedAccountId);
@@ -105,7 +61,7 @@ async function handler(args) {
105
61
  return process.exit(EXIT_CODES.ERROR);
106
62
  }
107
63
  if (buildIdToDeploy) {
108
- const validationResult = validateBuildId(buildIdToDeploy, deployedBuildId, latestBuild.buildId, projectName, targetAccountId);
64
+ const validationResult = validateBuildIdForDeploy(buildIdToDeploy, deployedBuildId, latestBuild.buildId, projectName, targetAccountId);
109
65
  if (validationResult !== true) {
110
66
  uiLogger.error(validationResult.toString());
111
67
  return process.exit(EXIT_CODES.ERROR);
@@ -122,7 +78,7 @@ async function handler(args) {
122
78
  default: latestBuild.buildId === deployedBuildId
123
79
  ? undefined
124
80
  : latestBuild.buildId,
125
- validate: buildId => validateBuildId(buildId, deployedBuildId, latestBuild.buildId, projectName, targetAccountId),
81
+ validate: buildId => validateBuildIdForDeploy(buildId, deployedBuildId, latestBuild.buildId, projectName, targetAccountId),
126
82
  });
127
83
  buildIdToDeploy = deployBuildIdPromptResponse.buildId;
128
84
  }
@@ -131,21 +87,13 @@ async function handler(args) {
131
87
  uiLogger.error(commands.project.deploy.errors.noBuildId);
132
88
  return process.exit(EXIT_CODES.ERROR);
133
89
  }
134
- const { data: deployResp } = await deployProject(targetAccountId, projectName, buildIdToDeploy, useV3Api(projectConfig?.platformVersion), forceOption);
135
- if (!deployResp || deployResp.buildResultType !== 'DEPLOY_QUEUED') {
136
- if (deployResp?.buildResultType === 'DEPLOY_BLOCKED') {
137
- handleBlockedDeploy(deployResp);
138
- process.exit(EXIT_CODES.ERROR);
139
- }
140
- else {
141
- uiLogger.error(commands.project.deploy.errors.deploy);
142
- }
90
+ const deployResult = await handleProjectDeploy(targetAccountId, projectName, buildIdToDeploy, useV3Api(projectConfig?.platformVersion), forceOption);
91
+ if (!deployResult) {
143
92
  return process.exit(EXIT_CODES.ERROR);
144
93
  }
145
94
  else if (formatOutputAsJson) {
146
- jsonOutput.deployId = Number(deployResp.id);
95
+ jsonOutput.deployId = deployResult.deployId;
147
96
  }
148
- const deployResult = await pollDeployStatus(targetAccountId, projectName, Number(deployResp.id), buildIdToDeploy);
149
97
  if (deployResult.status === PROJECT_DEPLOY_TEXT.STATES.SUCCESS) {
150
98
  deploySuccess = true;
151
99
  }
@@ -5,7 +5,7 @@ import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
5
5
  import { uiBetaTag, uiLine } from '../../../lib/ui/index.js';
6
6
  import { deprecatedProjectDevFlow } from './deprecatedFlow.js';
7
7
  import { unifiedProjectDevFlow } from './unifiedFlow.js';
8
- import { useV3Api } from '../../../lib/projects/buildAndDeploy.js';
8
+ import { useV3Api } from '../../../lib/projects/platformVersion.js';
9
9
  import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
10
10
  import { loadProfile, exitIfUsingProfiles, } from '../../../lib/projectProfiles.js';
11
11
  import { commands } from '../../../lang/en.js';
@@ -22,6 +22,7 @@ import LocalDevWebsocketServer from '../../../lib/projects/localDev/LocalDevWebs
22
22
  export async function unifiedProjectDevFlow({ args, targetProjectAccountId, providedTargetTestingAccountId, projectConfig, projectDir, }) {
23
23
  const env = getValidEnv(getEnv(targetProjectAccountId));
24
24
  let projectNodes;
25
+ let projectProfileData;
25
26
  // Get IR
26
27
  try {
27
28
  const intermediateRepresentation = await translateForLocalDev({
@@ -30,6 +31,7 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
30
31
  accountId: targetProjectAccountId,
31
32
  }, { profile: args.profile });
32
33
  projectNodes = intermediateRepresentation.intermediateNodesIndexedByUid;
34
+ projectProfileData = intermediateRepresentation.profileData;
33
35
  uiLogger.debug(util.inspect(projectNodes, false, null, true));
34
36
  }
35
37
  catch (e) {
@@ -116,6 +118,7 @@ export async function unifiedProjectDevFlow({ args, targetProjectAccountId, prov
116
118
  // End setup, start local dev process
117
119
  const localDevProcess = new LocalDevProcess({
118
120
  initialProjectNodes: projectNodes,
121
+ initialProjectProfileData: projectProfileData,
119
122
  debug: args.debug,
120
123
  profile: args.profile,
121
124
  targetProjectAccountId,
@@ -1,5 +1,5 @@
1
- import { CommonArgs, EnvironmentArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
2
- type ProjectUploadArgs = CommonArgs & JSONOutputArgs & EnvironmentArgs & {
1
+ import { CommonArgs, JSONOutputArgs, YargsCommandModule } from '../../types/Yargs.js';
2
+ type ProjectUploadArgs = CommonArgs & JSONOutputArgs & {
3
3
  forceCreate: boolean;
4
4
  message: string;
5
5
  m: string;
@@ -2,14 +2,14 @@ import chalk from 'chalk';
2
2
  import { logger } from '@hubspot/local-dev-lib/logger';
3
3
  import { getAccountConfig } from '@hubspot/local-dev-lib/config';
4
4
  import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
5
- import { useV3Api } from '../../lib/projects/buildAndDeploy.js';
5
+ import { useV3Api } from '../../lib/projects/platformVersion.js';
6
6
  import { uiBetaTag, uiCommandReference } from '../../lib/ui/index.js';
7
7
  import { trackCommandUsage } from '../../lib/usageTracking.js';
8
8
  import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
9
9
  import { logFeedbackMessage } from '../../lib/projects/ui.js';
10
10
  import { handleProjectUpload } from '../../lib/projects/upload.js';
11
11
  import { loadAndValidateProfile } from '../../lib/projectProfiles.js';
12
- import { displayWarnLogs, pollProjectBuildAndDeploy, } from '../../lib/projects/buildAndDeploy.js';
12
+ import { displayWarnLogs, pollProjectBuildAndDeploy, } from '../../lib/projects/pollProjectBuildAndDeploy.js';
13
13
  import { i18n } from '../../lib/lang.js';
14
14
  import { PROJECT_ERROR_TYPES } from '../../lib/constants.js';
15
15
  import { logError, ApiErrorContext } from '../../lib/errorHandlers/index.js';
@@ -25,7 +25,7 @@ async function handler(args) {
25
25
  validateProjectConfig(projectConfig, projectDir);
26
26
  let targetAccountId;
27
27
  if (useV3Api(projectConfig.platformVersion)) {
28
- targetAccountId = await loadAndValidateProfile(projectConfig, projectDir, profile, args.useEnv);
28
+ targetAccountId = await loadAndValidateProfile(projectConfig, projectDir, profile);
29
29
  }
30
30
  targetAccountId = targetAccountId || derivedAccountId;
31
31
  const accountConfig = getAccountConfig(targetAccountId);
@@ -1,6 +1,6 @@
1
1
  import path from 'path';
2
2
  import { getAccountConfig } from '@hubspot/local-dev-lib/config';
3
- import { useV3Api } from '../../lib/projects/buildAndDeploy.js';
3
+ import { useV3Api } from '../../lib/projects/platformVersion.js';
4
4
  import { trackCommandUsage } from '../../lib/usageTracking.js';
5
5
  import { uiLogger } from '../../lib/ui/logger.js';
6
6
  import { getProjectConfig, validateProjectConfig as validateProjectConfig, } from '../../lib/projects/config.js';
@@ -1,6 +1,6 @@
1
1
  import { cancelStagedBuild, fetchProjectBuilds, } from '@hubspot/local-dev-lib/api/projects';
2
2
  import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
3
- import { useV3Api } from '../../lib/projects/buildAndDeploy.js';
3
+ import { useV3Api } from '../../lib/projects/platformVersion.js';
4
4
  import { uiCommandReference, uiLink, uiBetaTag } from '../../lib/ui/index.js';
5
5
  import { i18n } from '../../lib/lang.js';
6
6
  import { createWatcher } from '../../lib/projects/watch.js';
@@ -11,7 +11,7 @@ import { trackCommandUsage } from '../../lib/usageTracking.js';
11
11
  import { getProjectConfig, validateProjectConfig, } from '../../lib/projects/config.js';
12
12
  import { logFeedbackMessage } from '../../lib/projects/ui.js';
13
13
  import { handleProjectUpload } from '../../lib/projects/upload.js';
14
- import { pollBuildStatus, pollDeployStatus, } from '../../lib/projects/buildAndDeploy.js';
14
+ import { pollBuildStatus, pollDeployStatus, } from '../../lib/projects/pollProjectBuildAndDeploy.js';
15
15
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
16
16
  import { handleKeypress, handleExit } from '../../lib/process.js';
17
17
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
@@ -75,9 +75,6 @@ async function handler(args) {
75
75
  resultJson.personalAccessKey = createResult.personalAccessKey;
76
76
  }
77
77
  catch (err) {
78
- SpinniesManager.fail('createTestAccount', {
79
- text: commands.testAccount.create.polling.createFailure,
80
- });
81
78
  logError(err);
82
79
  SpinniesManager.fail('createTestAccount', {
83
80
  text: commands.testAccount.create.polling.createFailure,
package/lang/en.d.ts CHANGED
@@ -23,7 +23,8 @@ export declare const commands: {
23
23
  };
24
24
  readonly startTitle: "Welcome to HubSpot Development!";
25
25
  readonly verboseDescribe: "A step-by-step command to get you started with a HubSpot project.";
26
- readonly startDescription: "You can use the HubSpot CLI to build apps, CMS themes, and more.";
26
+ readonly startDescription: "You can use the HubSpot CLI to build apps, CMS themes, and more.\n";
27
+ readonly guideOverview: (accountName: string) => string;
27
28
  readonly designManager: "To onboard with CMS, please visit the HubSpot Design Manager in your account and follow the checklist items.";
28
29
  readonly openDesignManager: "Click here to go to the HubSpot Design Manager";
29
30
  readonly openDesignManagerPrompt: "Open Design Manager in your browser?";
@@ -1188,9 +1189,11 @@ ${string}`;
1188
1189
  readonly success: (componentName: string, multiple?: boolean) => string;
1189
1190
  readonly error: {
1190
1191
  readonly failedToDownloadComponent: "Failed to download project. Please try again later.";
1192
+ readonly invalidComponentType: (componentType: string) => string;
1191
1193
  readonly maxExceeded: (maxCount: number) => string;
1192
1194
  readonly authTypeNotAllowed: (authType: string) => string;
1193
1195
  readonly distributionNotAllowed: (dist: string) => string;
1196
+ readonly portalDoesNotHaveAccessToThisFeature: (accountId: number) => string;
1194
1197
  readonly locationInProject: "This command must be run from within a project directory.";
1195
1198
  readonly failedToFetchComponentList: "Failed to fetch the list of available features. Please try again later.";
1196
1199
  readonly projectContainsPublicApp: "This project contains a public app. This command is currently only compatible with projects that contain private apps.";
@@ -1550,28 +1553,6 @@ ${string}`;
1550
1553
  readonly app: {
1551
1554
  readonly describe: "Commands for managing apps.";
1552
1555
  readonly subcommands: {
1553
- readonly install: {
1554
- readonly describe: "Install an OAuth app into a test account.";
1555
- readonly options: {
1556
- readonly appUid: "The uid of the app to install";
1557
- readonly projectName: "The name of the project that contains the app";
1558
- };
1559
- readonly positionals: {
1560
- readonly testAccountId: "The id of the test account to install the app into";
1561
- };
1562
- readonly errors: {
1563
- readonly mustSpecifyProjectName: `You must specify a project name. Use the ${string} flag to specify the project name or run this command from within a project directory.`;
1564
- readonly noAppUidFound: `No app uid found. Please specify the app uid with the ${string} flag or run this command from within a project that contains an app.`;
1565
- readonly appMustBeOauth: "This command only supports installing oauth apps. Please specify an app with oauth auth type.";
1566
- };
1567
- readonly polling: {
1568
- readonly start: "Installing app...";
1569
- readonly success: "App installed successfully";
1570
- readonly failure: "App installation failed";
1571
- readonly error: "Error installing app";
1572
- };
1573
- readonly example: "Install the app with uid my-app-uid from the project named \"my-project\" into the target account with id 1234567890";
1574
- };
1575
1556
  readonly secret: {
1576
1557
  readonly describe: "Commands for managing secrets.";
1577
1558
  readonly subcommands: {
@@ -3182,8 +3163,9 @@ Run ${string} to upgrade to version ${string}`;
3182
3163
  };
3183
3164
  };
3184
3165
  readonly installAppPrompt: {
3185
- readonly explanation: "Local development requires this app to be installed in the target test account";
3166
+ readonly explanation: "Local development requires this app to be installed in the target test account.";
3186
3167
  readonly reinstallExplanation: "This app's required scopes have been updated since it was last installed on the target test account. To avoid issues with local development, we recommend reinstalling the app with the updated scopes.";
3168
+ readonly staticAuthExplanation: (projectAccountId: number, testingAccountId: number, projectName: string, appUid: string) => string;
3187
3169
  readonly prompt: "Open HubSpot to install this app?";
3188
3170
  readonly autoPrompt: "Install this app in your target test account?";
3189
3171
  readonly reinstallPrompt: "Open HubSpot to reinstall this app?";
@@ -3404,7 +3386,7 @@ Run ${string} to upgrade to version ${string}`;
3404
3386
  readonly componentsToBeMigrated: (components: string) => string;
3405
3387
  readonly componentsThatWillNotBeMigrated: (components: string) => string;
3406
3388
  readonly sourceContentsMoved: (newLocation: string) => string;
3407
- readonly projectMigrationWarningTitle: "⚠️ Important: Migrating to platformVersion 2025.2 is irreversible ⚠️";
3389
+ readonly projectMigrationWarningTitle: "Important: Migrating to platformVersion 2025.2 is irreversible";
3408
3390
  readonly projectMigrationWarning: string;
3409
3391
  readonly success: {
3410
3392
  readonly downloadedProject: (projectName: string, projectDest: string) => string;
@@ -3419,7 +3401,7 @@ Run ${string} to upgrade to version ${string}`;
3419
3401
  readonly themesAndAppsNotAllowed: "Support for migrating projects containing both themes and apps to the latest platform version is coming soon. Try again later.";
3420
3402
  readonly multipleApps: "Multiple apps found in project, this is not allowed in 2025.2";
3421
3403
  readonly alreadyExists: (projectName: string) => string;
3422
- readonly failedToMigrateThemes: "Failed to migrate project themes. Please verify that you have propoerly formatted themes before trying again.";
3404
+ readonly failedToMigrateThemes: "Failed to migrate project themes. Please verify that your themes are properly formatted before trying again.";
3423
3405
  readonly failedToUpdateProjectConfig: "Failed to update project config file. Please update the platformVersion in the project config file manually.";
3424
3406
  };
3425
3407
  readonly unmigratableReasons: {
package/lang/en.js CHANGED
@@ -4,7 +4,7 @@ import { PLATFORM_VERSIONS } from '@hubspot/local-dev-lib/constants/projects';
4
4
  import { PERSONAL_ACCESS_KEY_AUTH_METHOD } from '@hubspot/local-dev-lib/constants/auth';
5
5
  import { ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME, GLOBAL_CONFIG_PATH, DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME, } from '@hubspot/local-dev-lib/constants/config';
6
6
  import { uiAccountDescription, uiBetaTag, uiCommandReference, uiLink, UI_COLORS, } from '../lib/ui/index.js';
7
- import { getProjectDetailUrl, getProjectSettingsUrl, getLocalDevUiUrl, } from '../lib/projects/urls.js';
7
+ import { getProjectDetailUrl, getProjectSettingsUrl, getLocalDevUiUrl, getAppAllowlistUrl, } from '../lib/projects/urls.js';
8
8
  import { APP_DISTRIBUTION_TYPES, APP_AUTH_TYPES, PROJECT_CONFIG_FILE, PROJECT_WITH_APP, } from '../lib/constants.js';
9
9
  import { getAccountIdentifier } from '@hubspot/local-dev-lib/config/getAccountIdentifier';
10
10
  export const commands = {
@@ -31,7 +31,8 @@ export const commands = {
31
31
  },
32
32
  startTitle: 'Welcome to HubSpot Development!',
33
33
  verboseDescribe: 'A step-by-step command to get you started with a HubSpot project.',
34
- startDescription: 'You can use the HubSpot CLI to build apps, CMS themes, and more.',
34
+ startDescription: 'You can use the HubSpot CLI to build apps, CMS themes, and more.\n',
35
+ guideOverview: (accountName) => `This guide will walk you through deploying your first project to ${chalk.bold(accountName)}.\nTo target a different account, exit this guide ${chalk.bold('(ctrl + c)')} and run ${uiCommandReference('hs account use')} before trying again.`,
35
36
  designManager: 'To onboard with CMS, please visit the HubSpot Design Manager in your account and follow the checklist items.',
36
37
  openDesignManager: 'Click here to go to the HubSpot Design Manager',
37
38
  openDesignManagerPrompt: 'Open Design Manager in your browser?',
@@ -1187,9 +1188,11 @@ export const commands = {
1187
1188
  success: (componentName, multiple = false) => `${componentName || 'An app'} ${multiple ? 'were' : 'was'} successfully added to your ${componentName ? 'app' : 'project'}.`,
1188
1189
  error: {
1189
1190
  failedToDownloadComponent: 'Failed to download project. Please try again later.',
1191
+ invalidComponentType: (componentType) => `'${componentType}' is not a valid project component type.`,
1190
1192
  maxExceeded: (maxCount) => `This project has the maximum allowed(${maxCount})`,
1191
1193
  authTypeNotAllowed: (authType) => `Auth type '${authType}' not allowed.`,
1192
1194
  distributionNotAllowed: (dist) => `Distribution '${dist}' not allowed.`,
1195
+ portalDoesNotHaveAccessToThisFeature: (accountId) => `The account ${uiAccountDescription(accountId)} does not have access to this feature`,
1193
1196
  locationInProject: 'This command must be run from within a project directory.',
1194
1197
  failedToFetchComponentList: 'Failed to fetch the list of available features. Please try again later.',
1195
1198
  projectContainsPublicApp: 'This project contains a public app. This command is currently only compatible with projects that contain private apps.',
@@ -1547,28 +1550,6 @@ export const commands = {
1547
1550
  app: {
1548
1551
  describe: 'Commands for managing apps.',
1549
1552
  subcommands: {
1550
- install: {
1551
- describe: 'Install an OAuth app into a test account.',
1552
- options: {
1553
- appUid: 'The uid of the app to install',
1554
- projectName: 'The name of the project that contains the app',
1555
- },
1556
- positionals: {
1557
- testAccountId: 'The id of the test account to install the app into',
1558
- },
1559
- errors: {
1560
- mustSpecifyProjectName: `You must specify a project name. Use the ${uiCommandReference('--project-name')} flag to specify the project name or run this command from within a project directory.`,
1561
- noAppUidFound: `No app uid found. Please specify the app uid with the ${uiCommandReference('--app-uid')} flag or run this command from within a project that contains an app.`,
1562
- appMustBeOauth: 'This command only supports installing oauth apps. Please specify an app with oauth auth type.',
1563
- },
1564
- polling: {
1565
- start: 'Installing app...',
1566
- success: 'App installed successfully',
1567
- failure: 'App installation failed',
1568
- error: 'Error installing app',
1569
- },
1570
- example: 'Install the app with uid my-app-uid from the project named "my-project" into the target account with id 1234567890',
1571
- },
1572
1553
  secret: {
1573
1554
  describe: 'Commands for managing secrets.',
1574
1555
  subcommands: {
@@ -3176,8 +3157,9 @@ export const lib = {
3176
3157
  },
3177
3158
  },
3178
3159
  installAppPrompt: {
3179
- explanation: 'Local development requires this app to be installed in the target test account',
3160
+ explanation: 'Local development requires this app to be installed in the target test account.',
3180
3161
  reinstallExplanation: "This app's required scopes have been updated since it was last installed on the target test account. To avoid issues with local development, we recommend reinstalling the app with the updated scopes.",
3162
+ staticAuthExplanation: (projectAccountId, testingAccountId, projectName, appUid) => `To install this static auth app, your testing account ${uiAccountDescription(testingAccountId)} must be on ${uiLink("this app's allowlist", getAppAllowlistUrl(projectAccountId, projectName, appUid))}.`,
3181
3163
  prompt: 'Open HubSpot to install this app?',
3182
3164
  autoPrompt: 'Install this app in your target test account?',
3183
3165
  reinstallPrompt: 'Open HubSpot to reinstall this app?',
@@ -3398,7 +3380,7 @@ export const lib = {
3398
3380
  componentsToBeMigrated: (components) => `The following features will be migrated: ${components}`,
3399
3381
  componentsThatWillNotBeMigrated: (components) => `[NOTE] These features are not yet supported for migration but will be available later: ${components}`,
3400
3382
  sourceContentsMoved: (newLocation) => `The contents of your old source directory have been moved to ${newLocation}, move any required files to the new source directory.`,
3401
- projectMigrationWarningTitle: '⚠️ Important: Migrating to platformVersion 2025.2 is irreversible ⚠️',
3383
+ projectMigrationWarningTitle: 'Important: Migrating to platformVersion 2025.2 is irreversible',
3402
3384
  projectMigrationWarning: uiBetaTag(`Running the ${uiCommandReference('hs project migrate')} command will permanently upgrade your project to platformVersion 2025.2. This action cannot be undone. To ensure you have access to your original files, they will be copied to a new directory (archive) for safekeeping.\n\nThis command will guide you through the process, prompting you to enter the required fields and will download the new project source code into your project source directory.`, false),
3403
3385
  success: {
3404
3386
  downloadedProject: (projectName, projectDest) => `Saved ${projectName} to ${projectDest}`,
@@ -3413,7 +3395,7 @@ export const lib = {
3413
3395
  themesAndAppsNotAllowed: 'Support for migrating projects containing both themes and apps to the latest platform version is coming soon. Try again later.',
3414
3396
  multipleApps: 'Multiple apps found in project, this is not allowed in 2025.2',
3415
3397
  alreadyExists: (projectName) => `A project with name ${projectName} already exists. Please choose another name.`,
3416
- failedToMigrateThemes: 'Failed to migrate project themes. Please verify that you have propoerly formatted themes before trying again.',
3398
+ failedToMigrateThemes: 'Failed to migrate project themes. Please verify that your themes are properly formatted before trying again.',
3417
3399
  failedToUpdateProjectConfig: 'Failed to update project config file. Please update the platformVersion in the project config file manually.',
3418
3400
  },
3419
3401
  unmigratableReasons: {