@hubspot/cli 7.7.32-experimental.0 → 7.7.34-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 (118) hide show
  1. package/commands/app/__tests__/install.test.js +47 -0
  2. package/commands/app/install.d.ts +8 -0
  3. package/commands/app/install.js +122 -0
  4. package/commands/app.js +6 -1
  5. package/commands/getStarted.js +7 -20
  6. package/commands/project/__tests__/add.test.js +3 -5
  7. package/commands/project/__tests__/deploy.test.js +3 -2
  8. package/commands/project/add.js +2 -4
  9. package/commands/project/deploy.js +9 -61
  10. package/commands/project/dev/index.js +1 -1
  11. package/commands/project/dev/unifiedFlow.js +4 -1
  12. package/commands/project/upload.d.ts +2 -2
  13. package/commands/project/upload.js +3 -3
  14. package/commands/project/validate.js +1 -1
  15. package/commands/project/watch.js +2 -2
  16. package/commands/testAccount/create.js +3 -0
  17. package/lang/en.d.ts +30 -4
  18. package/lang/en.js +31 -5
  19. package/lib/__tests__/hasFeature.test.js +145 -7
  20. package/lib/__tests__/importData.test.js +1 -1
  21. package/lib/app/migrate.js +9 -2
  22. package/lib/constants.d.ts +2 -0
  23. package/lib/constants.js +2 -0
  24. package/lib/errorHandlers/index.d.ts +4 -0
  25. package/lib/errorHandlers/index.js +1 -1
  26. package/lib/hasFeature.js +6 -0
  27. package/lib/importData.js +1 -1
  28. package/lib/mcp/setup.js +1 -1
  29. package/lib/projectProfiles.d.ts +1 -1
  30. package/lib/projectProfiles.js +10 -2
  31. package/lib/projects/__tests__/AppDevModeInterface.test.js +61 -44
  32. package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
  33. package/lib/projects/__tests__/deploy.test.d.ts +1 -0
  34. package/lib/projects/__tests__/deploy.test.js +164 -0
  35. package/lib/projects/__tests__/platformVersion.test.d.ts +1 -0
  36. package/lib/projects/__tests__/{buildAndDeploy.test.js → platformVersion.test.js} +2 -2
  37. package/lib/projects/add/__tests__/legacyAddComponent.test.js +49 -6
  38. package/lib/projects/add/__tests__/v3AddComponent.test.js +71 -1
  39. package/lib/projects/add/legacyAddComponent.d.ts +1 -1
  40. package/lib/projects/add/legacyAddComponent.js +5 -1
  41. package/lib/projects/add/v3AddComponent.d.ts +1 -0
  42. package/lib/projects/add/v3AddComponent.js +2 -2
  43. package/lib/projects/create/__tests__/v3.test.js +97 -9
  44. package/lib/projects/create/index.js +2 -2
  45. package/lib/projects/create/legacy.js +1 -1
  46. package/lib/projects/create/v3.d.ts +2 -2
  47. package/lib/projects/create/v3.js +35 -12
  48. package/lib/projects/deploy.d.ts +13 -0
  49. package/lib/projects/deploy.js +63 -0
  50. package/lib/projects/localDev/AppDevModeInterface.d.ts +0 -2
  51. package/lib/projects/localDev/AppDevModeInterface.js +65 -36
  52. package/lib/projects/localDev/DevServerManagerV2.js +1 -0
  53. package/lib/projects/localDev/LocalDevProcess.js +3 -1
  54. package/lib/projects/localDev/LocalDevState.d.ts +5 -2
  55. package/lib/projects/localDev/LocalDevState.js +9 -1
  56. package/lib/projects/localDev/helpers/project.d.ts +2 -2
  57. package/lib/projects/localDev/helpers/project.js +6 -7
  58. package/lib/projects/platformVersion.d.ts +1 -0
  59. package/lib/projects/platformVersion.js +10 -0
  60. package/lib/projects/{buildAndDeploy.d.ts → pollProjectBuildAndDeploy.d.ts} +0 -1
  61. package/lib/projects/{buildAndDeploy.js → pollProjectBuildAndDeploy.js} +0 -10
  62. package/lib/projects/structure.d.ts +2 -2
  63. package/lib/projects/upload.d.ts +2 -1
  64. package/lib/projects/upload.js +2 -1
  65. package/lib/projects/urls.d.ts +1 -0
  66. package/lib/projects/urls.js +3 -0
  67. package/lib/prompts/__tests__/projectAddPrompt.test.d.ts +1 -0
  68. package/lib/prompts/__tests__/projectAddPrompt.test.js +143 -0
  69. package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.d.ts +1 -0
  70. package/lib/prompts/__tests__/selectProjectTemplatePrompt.test.js +160 -0
  71. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +1 -0
  72. package/lib/prompts/importDataFilePathPrompt.js +4 -2
  73. package/lib/prompts/installAppPrompt.d.ts +6 -1
  74. package/lib/prompts/installAppPrompt.js +6 -1
  75. package/lib/prompts/projectAddPrompt.js +1 -1
  76. package/lib/prompts/selectProjectTemplatePrompt.js +1 -1
  77. package/mcp-server/tools/cms/HsCreateFunctionTool.js +1 -1
  78. package/mcp-server/tools/cms/HsCreateModuleTool.js +1 -1
  79. package/mcp-server/tools/cms/HsCreateTemplateTool.js +1 -1
  80. package/mcp-server/tools/cms/HsFunctionLogsTool.d.ts +32 -0
  81. package/mcp-server/tools/cms/HsFunctionLogsTool.js +76 -0
  82. package/mcp-server/tools/cms/HsListFunctionsTool.js +1 -1
  83. package/mcp-server/tools/cms/HsListTool.js +1 -1
  84. package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -1
  85. package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +1 -1
  86. package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +1 -1
  87. package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.d.ts +1 -0
  88. package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +183 -0
  89. package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +1 -1
  90. package/mcp-server/tools/cms/__tests__/HsListTool.test.js +1 -1
  91. package/mcp-server/tools/index.js +2 -0
  92. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +3 -3
  93. package/mcp-server/tools/project/AddFeatureToProjectTool.js +3 -3
  94. package/mcp-server/tools/project/CreateProjectTool.d.ts +3 -3
  95. package/mcp-server/tools/project/CreateProjectTool.js +5 -5
  96. package/mcp-server/tools/project/DeployProjectTool.js +1 -1
  97. package/mcp-server/tools/project/DocFetchTool.js +2 -2
  98. package/mcp-server/tools/project/DocsSearchTool.js +2 -2
  99. package/mcp-server/tools/project/GetConfigValuesTool.js +4 -4
  100. package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -1
  101. package/mcp-server/tools/project/UploadProjectTools.js +2 -2
  102. package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
  103. package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +1 -1
  104. package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -1
  105. package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +1 -1
  106. package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +2 -2
  107. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +2 -2
  108. package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +1 -1
  109. package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +1 -1
  110. package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +1 -1
  111. package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +1 -1
  112. package/mcp-server/tools/project/constants.d.ts +1 -1
  113. package/mcp-server/tools/project/constants.js +14 -6
  114. package/package.json +3 -3
  115. package/types/LocalDev.d.ts +2 -1
  116. package/types/Projects.d.ts +1 -0
  117. package/types/Yargs.d.ts +1 -1
  118. /package/{lib/projects/__tests__/buildAndDeploy.test.d.ts → commands/app/__tests__/install.test.d.ts} +0 -0
@@ -1,13 +1,15 @@
1
1
  import { Separator } from '@inquirer/prompts';
2
- import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, EMPTY_PROJECT, PROJECT_WITH_APP, } from '../../constants.js';
2
+ import { marketplaceDistribution, oAuth, privateDistribution, staticAuth, EMPTY_PROJECT, PROJECT_WITH_APP, FEATURES, } from '../../constants.js';
3
3
  import { commands, lib } from '../../../lang/en.js';
4
4
  import { listPrompt } from '../../prompts/promptUtils.js';
5
5
  import chalk from 'chalk';
6
- import { useV3Api } from '../buildAndDeploy.js';
6
+ import { useV3Api } from '../platformVersion.js';
7
7
  import path from 'path';
8
8
  import { getConfigForPlatformVersion } from './legacy.js';
9
9
  import { logError } from '../../errorHandlers/index.js';
10
10
  import { EXIT_CODES } from '../../enums/exitCodes.js';
11
+ import { hasFeature } from '../../hasFeature.js';
12
+ import { AppEventsKey, PagesKey, } from '@hubspot/project-parsing-lib/src/lib/constants.js';
11
13
  export async function createV3App(providedAuth, providedDistribution) {
12
14
  let authType;
13
15
  if (providedAuth &&
@@ -47,16 +49,26 @@ export async function createV3App(providedAuth, providedDistribution) {
47
49
  authType: authType,
48
50
  };
49
51
  }
50
- export function calculateComponentTemplateChoices(components, authType, distribution, projectMetadata) {
52
+ const componentTypeToGateMap = {
53
+ [AppEventsKey]: FEATURES.APP_EVENTS,
54
+ [PagesKey]: FEATURES.APPS_HOME,
55
+ };
56
+ export async function calculateComponentTemplateChoices(components, authType, distribution, accountId, projectMetadata) {
51
57
  const enabledComponents = [];
52
58
  const disabledComponents = [];
53
- components.forEach(template => {
59
+ for (const template of components) {
54
60
  const { supportedAuthTypes, supportedDistributions } = template;
55
61
  const disabledReasons = [];
56
62
  if (projectMetadata) {
57
- const { count, maxCount } = projectMetadata.components[template.type];
58
- if (count >= maxCount) {
59
- disabledReasons.push(commands.project.add.error.maxExceeded(maxCount));
63
+ const componentMetadata = projectMetadata.components[template.type];
64
+ if (!componentMetadata) {
65
+ disabledReasons.push(commands.project.add.error.invalidComponentType(template.type));
66
+ }
67
+ else {
68
+ const { count, maxCount } = componentMetadata;
69
+ if (count >= maxCount) {
70
+ disabledReasons.push(commands.project.add.error.maxExceeded(maxCount));
71
+ }
60
72
  }
61
73
  }
62
74
  if (Array.isArray(supportedAuthTypes) &&
@@ -69,9 +81,15 @@ export function calculateComponentTemplateChoices(components, authType, distribu
69
81
  !supportedDistributions.includes(distribution)) {
70
82
  disabledReasons.push(commands.project.add.error.distributionNotAllowed(distribution));
71
83
  }
84
+ if (componentTypeToGateMap[template.type]) {
85
+ const isUngated = await hasFeature(accountId, componentTypeToGateMap[template.type]);
86
+ if (!isUngated) {
87
+ disabledReasons.push(commands.project.add.error.portalDoesNotHaveAccessToThisFeature(accountId));
88
+ }
89
+ }
72
90
  if (disabledReasons.length > 0) {
73
91
  disabledComponents.push({
74
- name: `[${chalk.yellow('DISABLED')}] ${template.label}`,
92
+ name: `[${chalk.yellow('DISABLED')}] ${template.label} -`,
75
93
  value: template,
76
94
  disabled: disabledReasons.join(' '),
77
95
  });
@@ -82,12 +100,17 @@ export function calculateComponentTemplateChoices(components, authType, distribu
82
100
  value: template,
83
101
  });
84
102
  }
85
- });
103
+ }
86
104
  return disabledComponents.length
87
- ? [...enabledComponents, new Separator(), ...disabledComponents]
105
+ ? [
106
+ ...enabledComponents,
107
+ new Separator(),
108
+ ...disabledComponents,
109
+ new Separator(),
110
+ ]
88
111
  : [...enabledComponents];
89
112
  }
90
- export async function v3ComponentFlow(platformVersion, projectBase, providedAuth, providedDistribution) {
113
+ export async function v3ComponentFlow(platformVersion, projectBase, providedAuth, providedDistribution, accountId) {
91
114
  let repoConfig = undefined;
92
115
  let authType;
93
116
  let distribution;
@@ -113,7 +136,7 @@ export async function v3ComponentFlow(platformVersion, projectBase, providedAuth
113
136
  authType = selectedAuthType;
114
137
  distribution = selectedDistribution;
115
138
  }
116
- const componentTemplateChoices = calculateComponentTemplateChoices(repoConfig?.components || [], authType, distribution);
139
+ const componentTemplateChoices = await calculateComponentTemplateChoices(repoConfig?.components || [], authType, distribution, accountId);
117
140
  return {
118
141
  componentTemplateChoices,
119
142
  authType,
@@ -0,0 +1,13 @@
1
+ import { Deploy } from '@hubspot/local-dev-lib/types/Deploy';
2
+ export declare function validateBuildIdForDeploy(buildId: number, deployedBuildId: number | undefined, latestBuildId: number, projectName: string | undefined, accountId: number): boolean | string;
3
+ export declare function logDeployErrors(errorData: {
4
+ message: string;
5
+ errors: Array<{
6
+ message: string;
7
+ subCategory: string;
8
+ context: {
9
+ COMPONENT_NAME: string;
10
+ };
11
+ }>;
12
+ }): void;
13
+ export declare function handleProjectDeploy(targetAccountId: number, projectName: string, buildId: number, useV3Api: boolean, force: boolean): Promise<Deploy | undefined>;
@@ -0,0 +1,63 @@
1
+ import { uiLogger } from '../ui/logger.js';
2
+ import { commands } from '../../lang/en.js';
3
+ import { PROJECT_ERROR_TYPES } from '../constants.js';
4
+ import { deployProject } from '@hubspot/local-dev-lib/api/projects';
5
+ import { pollDeployStatus } from './pollProjectBuildAndDeploy.js';
6
+ export function validateBuildIdForDeploy(buildId, deployedBuildId, latestBuildId, projectName, accountId) {
7
+ if (Number(buildId) > latestBuildId) {
8
+ return commands.project.deploy.errors.buildIdDoesNotExist(accountId, buildId, projectName);
9
+ }
10
+ if (Number(buildId) === deployedBuildId) {
11
+ return commands.project.deploy.errors.buildAlreadyDeployed(accountId, buildId, projectName);
12
+ }
13
+ return true;
14
+ }
15
+ export function logDeployErrors(errorData) {
16
+ uiLogger.error(errorData.message);
17
+ errorData.errors.forEach(err => {
18
+ // This is how the pre-deploy check manifests itself in < 2025.2 projects
19
+ if (err.subCategory === PROJECT_ERROR_TYPES.DEPLOY_CONTAINS_REMOVALS) {
20
+ uiLogger.log(commands.project.deploy.errors.deployContainsRemovals(err.context.COMPONENT_NAME));
21
+ }
22
+ else {
23
+ uiLogger.log(err.message);
24
+ }
25
+ });
26
+ }
27
+ function handleBlockedDeploy(deployResp) {
28
+ const deployCanBeForced = deployResp.issues.every(issue => issue.blockingMessages.every(message => message.isWarning));
29
+ uiLogger.log('');
30
+ if (deployCanBeForced) {
31
+ uiLogger.warn(commands.project.deploy.errors.deployWarningsHeader);
32
+ uiLogger.log('');
33
+ }
34
+ else {
35
+ uiLogger.error(commands.project.deploy.errors.deployBlockedHeader);
36
+ uiLogger.log('');
37
+ }
38
+ deployResp.issues.forEach(issue => {
39
+ if (issue.blockingMessages.length > 0) {
40
+ issue.blockingMessages.forEach(message => {
41
+ uiLogger.log(commands.project.deploy.errors.deployIssueComponentWarning(issue.uid, issue.componentTypeName, message.message));
42
+ });
43
+ }
44
+ else {
45
+ uiLogger.log(commands.project.deploy.errors.deployIssueComponentGeneric(issue.uid, issue.componentTypeName));
46
+ }
47
+ uiLogger.log('');
48
+ });
49
+ }
50
+ export async function handleProjectDeploy(targetAccountId, projectName, buildId, useV3Api, force) {
51
+ const { data: deployResp } = await deployProject(targetAccountId, projectName, buildId, useV3Api, force);
52
+ if (!deployResp || deployResp.buildResultType !== 'DEPLOY_QUEUED') {
53
+ if (deployResp?.buildResultType === 'DEPLOY_BLOCKED') {
54
+ handleBlockedDeploy(deployResp);
55
+ }
56
+ else {
57
+ uiLogger.error(commands.project.deploy.errors.deploy);
58
+ }
59
+ return;
60
+ }
61
+ const deployResult = await pollDeployStatus(targetAccountId, projectName, Number(deployResp.id), buildId);
62
+ return deployResult;
63
+ }
@@ -15,11 +15,9 @@ declare class AppDevModeInterface {
15
15
  private get appNode();
16
16
  private get appData();
17
17
  private set appData(value);
18
- private isAutomaticallyInstallable;
19
18
  private getAppInstallUrl;
20
19
  private fetchAppData;
21
20
  private checkMarketplaceAppInstalls;
22
- private autoInstallStaticAuthApp;
23
21
  private installAppOrOpenInstallUrl;
24
22
  private checkTestAccountAppInstallation;
25
23
  private onDevServerMessage;
@@ -1,19 +1,21 @@
1
1
  import { fetchAppInstallationData } from '@hubspot/local-dev-lib/api/localDevAuth';
2
- import { fetchPublicAppsForPortal, fetchPublicAppProductionInstallCounts, installStaticAuthAppOnTestAccount, } from '@hubspot/local-dev-lib/api/appsDev';
2
+ import { fetchPublicAppsForPortal, fetchPublicAppProductionInstallCounts,
3
+ // installStaticAuthAppOnTestAccount,
4
+ } from '@hubspot/local-dev-lib/api/appsDev';
3
5
  import { DevModeUnifiedInterface as UIEDevModeInterface } from '@hubspot/ui-extensions-dev-server';
4
6
  import { requestPorts } from '@hubspot/local-dev-lib/portManager';
5
- import { getAccountConfig } from '@hubspot/local-dev-lib/config';
6
7
  import { APP_AUTH_TYPES, APP_DISTRIBUTION_TYPES, APP_INSTALLATION_STATES, LOCAL_DEV_SERVER_MESSAGE_TYPES, } from '../../constants.js';
7
8
  import { EXIT_CODES } from '../../enums/exitCodes.js';
8
9
  import { isAppIRNode } from '../../projects/structure.js';
9
10
  import { uiLine } from '../../ui/index.js';
10
11
  import { logError } from '../../errorHandlers/index.js';
11
- import { installAppAutoPrompt, installAppBrowserPrompt, } from '../../prompts/installAppPrompt.js';
12
+ import {
13
+ // installAppAutoPrompt,
14
+ installAppBrowserPrompt, } from '../../prompts/installAppPrompt.js';
12
15
  import { confirmPrompt } from '../../prompts/promptUtils.js';
13
16
  import { lib } from '../../../lang/en.js';
14
17
  import { uiLogger } from '../../ui/logger.js';
15
18
  import { getOauthAppInstallUrl, getStaticAuthAppInstallUrl, } from '../../app/urls.js';
16
- import { isDeveloperTestAccount, isSandbox } from '../../accountTypes.js';
17
19
  import SpinniesManager from '../../ui/SpinniesManager.js';
18
20
  class AppDevModeInterface {
19
21
  localDevState;
@@ -52,19 +54,26 @@ class AppDevModeInterface {
52
54
  }
53
55
  this.localDevState.setAppDataForUid(this.appNode.uid, appData);
54
56
  }
55
- isAutomaticallyInstallable() {
56
- const targetTestingAccount = getAccountConfig(this.localDevState.targetTestingAccountId);
57
- if (!targetTestingAccount) {
58
- return false;
59
- }
60
- const isTestAccount = isDeveloperTestAccount(targetTestingAccount) ||
61
- isSandbox(targetTestingAccount);
62
- const hasCorrectParent = targetTestingAccount.parentAccountId ===
63
- this.localDevState.targetProjectAccountId;
64
- return (isTestAccount &&
65
- hasCorrectParent &&
66
- this.appNode?.config.auth.type === APP_AUTH_TYPES.STATIC);
67
- }
57
+ // @TODO: Restore test account auto install functionality
58
+ // private isAutomaticallyInstallable(): boolean {
59
+ // const targetTestingAccount = getAccountConfig(
60
+ // this.localDevState.targetTestingAccountId
61
+ // );
62
+ // if (!targetTestingAccount) {
63
+ // return false;
64
+ // }
65
+ // const isTestAccount =
66
+ // isDeveloperTestAccount(targetTestingAccount) ||
67
+ // isSandbox(targetTestingAccount);
68
+ // const hasCorrectParent =
69
+ // targetTestingAccount.parentAccountId ===
70
+ // this.localDevState.targetProjectAccountId;
71
+ // return (
72
+ // isTestAccount &&
73
+ // hasCorrectParent &&
74
+ // this.appNode?.config.auth.type === APP_AUTH_TYPES.STATIC
75
+ // );
76
+ // }
68
77
  async getAppInstallUrl() {
69
78
  if (this.appNode?.config.auth.type === APP_AUTH_TYPES.OAUTH) {
70
79
  return getOauthAppInstallUrl({
@@ -134,27 +143,47 @@ class AppDevModeInterface {
134
143
  }
135
144
  this.localDevState.addUploadWarning(lib.AppDevModeInterface.defaultMarketplaceAppWarning(this.marketplaceAppInstalls));
136
145
  }
137
- async autoInstallStaticAuthApp() {
138
- const shouldInstall = await installAppAutoPrompt();
139
- if (!shouldInstall) {
140
- uiLogger.log(lib.AppDevModeInterface.autoInstallDeclined);
141
- process.exit(EXIT_CODES.SUCCESS);
142
- }
143
- await installStaticAuthAppOnTestAccount(this.appData.id, this.localDevState.targetTestingAccountId, this.appData.scopeGroupIds);
144
- }
146
+ // @TODO: Restore test account auto install functionality
147
+ // private async autoInstallStaticAuthApp(): Promise<void> {
148
+ // const shouldInstall = await installAppAutoPrompt();
149
+ // if (!shouldInstall) {
150
+ // uiLogger.log(lib.AppDevModeInterface.autoInstallDeclined);
151
+ // process.exit(EXIT_CODES.SUCCESS);
152
+ // }
153
+ // await installStaticAuthAppOnTestAccount(
154
+ // this.appData!.id,
155
+ // this.localDevState.targetTestingAccountId,
156
+ // this.appData!.scopeGroupIds
157
+ // );
158
+ // }
145
159
  async installAppOrOpenInstallUrl(isReinstall) {
146
- if (this.isAutomaticallyInstallable()) {
147
- try {
148
- await this.autoInstallStaticAuthApp();
149
- uiLogger.success(lib.AppDevModeInterface.autoInstallSuccess(this.appData.name, this.localDevState.targetTestingAccountId));
150
- return;
151
- }
152
- catch (e) {
153
- uiLogger.error(lib.AppDevModeInterface.autoInstallError(this.appData.name, this.localDevState.targetTestingAccountId));
154
- }
155
- }
160
+ // @TODO: Restore test account auto install functionality
161
+ // if (this.isAutomaticallyInstallable()) {
162
+ // try {
163
+ // await this.autoInstallStaticAuthApp();
164
+ // uiLogger.success(
165
+ // lib.AppDevModeInterface.autoInstallSuccess(
166
+ // this.appData!.name,
167
+ // this.localDevState.targetTestingAccountId
168
+ // )
169
+ // );
170
+ // return;
171
+ // } catch (e) {
172
+ // uiLogger.error(
173
+ // lib.AppDevModeInterface.autoInstallError(
174
+ // this.appData!.name,
175
+ // this.localDevState.targetTestingAccountId
176
+ // )
177
+ // );
178
+ // }
179
+ // }
156
180
  const installUrl = await this.getAppInstallUrl();
157
- await installAppBrowserPrompt(installUrl, isReinstall);
181
+ await installAppBrowserPrompt(installUrl, isReinstall, {
182
+ testingAccountId: this.localDevState.targetTestingAccountId,
183
+ projectAccountId: this.localDevState.targetProjectAccountId,
184
+ projectName: this.localDevState.projectConfig.name,
185
+ appUid: this.appNode.uid,
186
+ });
158
187
  }
159
188
  async checkTestAccountAppInstallation() {
160
189
  if (!this.appNode || !this.appData) {
@@ -34,6 +34,7 @@ class DevServerManagerV2 {
34
34
  // @TODO: In the future, update UIE Dev Server to use LocalDevState
35
35
  await serverInterface.setup({
36
36
  components: this.localDevState.projectNodes,
37
+ profileData: this.localDevState.projectProfileData,
37
38
  logger,
38
39
  urls: {
39
40
  api: getHubSpotApiOrigin(env),
@@ -8,7 +8,7 @@ import DevServerManagerV2 from './DevServerManagerV2.js';
8
8
  import { EXIT_CODES } from '../../enums/exitCodes.js';
9
9
  import { getProjectConfig } from '../config.js';
10
10
  import { handleProjectUpload } from '../upload.js';
11
- import { pollProjectBuildAndDeploy } from '../buildAndDeploy.js';
11
+ import { pollProjectBuildAndDeploy } from '../pollProjectBuildAndDeploy.js';
12
12
  import { getLocalDevUiUrl } from '../urls.js';
13
13
  import { CONFIG_LOCAL_STATE_FLAGS } from '../../constants.js';
14
14
  import { isAutoOpenBrowserEnabled } from '../../configOptions.js';
@@ -101,11 +101,13 @@ class LocalDevProcess {
101
101
  const intermediateRepresentation = await this.getIntermediateRepresentation(this.state.projectNodesAtLastUpload);
102
102
  this.state.projectNodes =
103
103
  intermediateRepresentation.intermediateNodesIndexedByUid;
104
+ this.state.projectProfileData = intermediateRepresentation.profileData;
104
105
  }
105
106
  async updateProjectNodesAfterUpload() {
106
107
  const intermediateRepresentation = await this.getIntermediateRepresentation();
107
108
  this.state.projectNodes =
108
109
  intermediateRepresentation.intermediateNodesIndexedByUid;
110
+ this.state.projectProfileData = intermediateRepresentation.profileData;
109
111
  this.state.projectNodesAtLastUpload =
110
112
  intermediateRepresentation.intermediateNodesIndexedByUid;
111
113
  }
@@ -1,4 +1,4 @@
1
- import { IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types.js';
1
+ import { IntermediateRepresentationNodeLocalDev, HSProfileVariables } from '@hubspot/project-parsing-lib/src/lib/types.js';
2
2
  import { Environment } from '@hubspot/local-dev-lib/types/Config';
3
3
  import { ProjectConfig } from '../../../types/Projects.js';
4
4
  import { LocalDevStateConstructorOptions, LocalDevStateListener, AppLocalDevData, LocalDevServerMessage } from '../../../types/LocalDev.js';
@@ -12,13 +12,14 @@ declare class LocalDevState {
12
12
  private _projectName;
13
13
  private _debug;
14
14
  private _projectNodes;
15
+ private _projectProfileData;
15
16
  private _projectNodesAtLastUpload;
16
17
  private _env;
17
18
  private _listeners;
18
19
  private _appData;
19
20
  private _devServerMessage;
20
21
  private _uploadWarnings;
21
- constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, initialProjectNodes, profile, env, }: LocalDevStateConstructorOptions);
22
+ constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, initialProjectNodes, initialProjectProfileData, profile, env, }: LocalDevStateConstructorOptions);
22
23
  private runListeners;
23
24
  get targetProjectAccountId(): number;
24
25
  get targetTestingAccountId(): number;
@@ -34,6 +35,8 @@ declare class LocalDevState {
34
35
  set projectNodes(nodes: {
35
36
  [key: string]: IntermediateRepresentationNodeLocalDev;
36
37
  });
38
+ get projectProfileData(): HSProfileVariables;
39
+ set projectProfileData(profileData: HSProfileVariables);
37
40
  get projectNodesAtLastUpload(): {
38
41
  [key: string]: IntermediateRepresentationNodeLocalDev;
39
42
  };
@@ -9,13 +9,14 @@ class LocalDevState {
9
9
  _projectName;
10
10
  _debug;
11
11
  _projectNodes;
12
+ _projectProfileData;
12
13
  _projectNodesAtLastUpload;
13
14
  _env;
14
15
  _listeners;
15
16
  _appData;
16
17
  _devServerMessage;
17
18
  _uploadWarnings;
18
- constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, initialProjectNodes, profile, env, }) {
19
+ constructor({ targetProjectAccountId, targetTestingAccountId, projectConfig, projectDir, projectId, projectName, debug, initialProjectNodes, initialProjectProfileData, profile, env, }) {
19
20
  this._targetProjectAccountId = targetProjectAccountId;
20
21
  this._targetTestingAccountId = targetTestingAccountId;
21
22
  this._profile = profile;
@@ -26,6 +27,7 @@ class LocalDevState {
26
27
  this._debug = debug || false;
27
28
  this._projectNodes = initialProjectNodes;
28
29
  this._projectNodesAtLastUpload = initialProjectNodes;
30
+ this._projectProfileData = initialProjectProfileData;
29
31
  this._env = env;
30
32
  this._appData = {};
31
33
  this._devServerMessage = LOCAL_DEV_SERVER_MESSAGE_TYPES.INITIAL;
@@ -68,6 +70,12 @@ class LocalDevState {
68
70
  this._projectNodes = nodes;
69
71
  this.runListeners('projectNodes');
70
72
  }
73
+ get projectProfileData() {
74
+ return structuredClone(this._projectProfileData);
75
+ }
76
+ set projectProfileData(profileData) {
77
+ this._projectProfileData = profileData;
78
+ }
71
79
  get projectNodesAtLastUpload() {
72
80
  return structuredClone(this._projectNodesAtLastUpload);
73
81
  }
@@ -6,7 +6,7 @@ export declare function createNewProjectForLocalDev(projectConfig: ProjectConfig
6
6
  export declare function createInitialBuildForNewProject(projectConfig: ProjectConfig, projectDir: string, targetAccountId: number, sendIR?: boolean, profile?: string): Promise<Build>;
7
7
  export declare function compareLocalProjectToDeployed(projectConfig: ProjectConfig, accountId: number, deployedBuildId: number | undefined, localProjectNodes: {
8
8
  [key: string]: IntermediateRepresentationNodeLocalDev;
9
- }): Promise<void>;
9
+ }, profile?: string): Promise<void>;
10
10
  export declare function isDeployedProjectUpToDateWithLocal(projectConfig: ProjectConfig, accountId: number, deployedBuildId: number, localProjectNodes: {
11
11
  [key: string]: IntermediateRepresentationNodeLocalDev;
12
- }): Promise<boolean>;
12
+ }, profile?: string): Promise<boolean>;
@@ -17,7 +17,7 @@ import { uiAccountDescription } from '../../../ui/index.js';
17
17
  import SpinniesManager from '../../../ui/SpinniesManager.js';
18
18
  import { EXIT_CODES } from '../../../enums/exitCodes.js';
19
19
  import { handleProjectUpload } from '../../upload.js';
20
- import { pollProjectBuildAndDeploy } from '../../buildAndDeploy.js';
20
+ import { pollProjectBuildAndDeploy } from '../../pollProjectBuildAndDeploy.js';
21
21
  import { logError } from '../../../errorHandlers/index.js';
22
22
  import { ApiErrorContext } from '../../../errorHandlers/index.js';
23
23
  // Prompt the user to create a new project if one doesn't exist on their target account
@@ -123,7 +123,7 @@ export async function createInitialBuildForNewProject(projectConfig, projectDir,
123
123
  }
124
124
  return initialUploadResult.buildResult;
125
125
  }
126
- export async function compareLocalProjectToDeployed(projectConfig, accountId, deployedBuildId, localProjectNodes) {
126
+ export async function compareLocalProjectToDeployed(projectConfig, accountId, deployedBuildId, localProjectNodes, profile) {
127
127
  uiLogger.log('');
128
128
  if (!deployedBuildId) {
129
129
  uiLogger.error(lib.localDevHelpers.project.compareLocalProjectToDeployed.noDeployedBuild(projectConfig.name, uiAccountDescription(accountId)));
@@ -132,7 +132,7 @@ export async function compareLocalProjectToDeployed(projectConfig, accountId, de
132
132
  SpinniesManager.add('compareLocalProjectToDeployed', {
133
133
  text: lib.localDevHelpers.project.compareLocalProjectToDeployed.checking,
134
134
  });
135
- const isUpToDate = await isDeployedProjectUpToDateWithLocal(projectConfig, accountId, deployedBuildId, localProjectNodes);
135
+ const isUpToDate = await isDeployedProjectUpToDateWithLocal(projectConfig, accountId, deployedBuildId, localProjectNodes, profile);
136
136
  if (isUpToDate) {
137
137
  SpinniesManager.succeed('compareLocalProjectToDeployed', {
138
138
  text: lib.localDevHelpers.project.compareLocalProjectToDeployed.upToDate,
@@ -144,12 +144,11 @@ export async function compareLocalProjectToDeployed(projectConfig, accountId, de
144
144
  .notUpToDate,
145
145
  });
146
146
  uiLogger.log('');
147
- uiLogger.log(lib.localDevHelpers.project.compareLocalProjectToDeployed
148
- .notUpToDateExplanation);
147
+ uiLogger.log(lib.localDevHelpers.project.compareLocalProjectToDeployed.notUpToDateExplanation(profile));
149
148
  process.exit(EXIT_CODES.SUCCESS);
150
149
  }
151
150
  }
152
- export async function isDeployedProjectUpToDateWithLocal(projectConfig, accountId, deployedBuildId, localProjectNodes) {
151
+ export async function isDeployedProjectUpToDateWithLocal(projectConfig, accountId, deployedBuildId, localProjectNodes, profile) {
153
152
  let tempDir = null;
154
153
  try {
155
154
  tempDir = await fs.mkdtemp(path.join(os.tmpdir(), 'hubspot-project-compare-'));
@@ -161,7 +160,7 @@ export async function isDeployedProjectUpToDateWithLocal(projectConfig, accountI
161
160
  projectSourceDir: deployedProjectSourceDir,
162
161
  platformVersion: projectConfig.platformVersion,
163
162
  accountId: accountId,
164
- }, {});
163
+ }, { profile });
165
164
  return isDeepEqual(localProjectNodes, deployedProjectNodes, ['localDev']);
166
165
  }
167
166
  finally {
@@ -0,0 +1 @@
1
+ export declare function useV3Api(platformVersion?: string | null): boolean;
@@ -0,0 +1,10 @@
1
+ export function useV3Api(platformVersion) {
2
+ if (!platformVersion || typeof platformVersion !== 'string') {
3
+ return false;
4
+ }
5
+ if (platformVersion.toLowerCase() === 'unstable') {
6
+ return true;
7
+ }
8
+ const [year, minor] = platformVersion.split('.');
9
+ return Number(year) >= 2025 && Number(minor) >= 2;
10
+ }
@@ -2,7 +2,6 @@ import { FileResult } from 'tmp';
2
2
  import { Build } from '@hubspot/local-dev-lib/types/Build';
3
3
  import { Deploy } from '@hubspot/local-dev-lib/types/Deploy';
4
4
  import { ProjectConfig, ProjectTask, ProjectPollResult } from '../../types/Projects.js';
5
- export declare function useV3Api(platformVersion?: string | null): boolean;
6
5
  type PollTaskStatusFunction<T extends ProjectTask> = (accountId: number, taskName: string, taskId: number, deployedBuildId: number | null, silenceLogs?: boolean) => Promise<T>;
7
6
  export declare const pollBuildStatus: PollTaskStatusFunction<Build>;
8
7
  export declare const pollDeployStatus: PollTaskStatusFunction<Deploy>;
@@ -13,16 +13,6 @@ import { mapToInternalType } from '@hubspot/project-parsing-lib';
13
13
  const SPINNER_STATUS = {
14
14
  SPINNING: 'spinning',
15
15
  };
16
- export function useV3Api(platformVersion) {
17
- if (!platformVersion || typeof platformVersion !== 'string') {
18
- return false;
19
- }
20
- if (platformVersion.toLowerCase() === 'unstable') {
21
- return true;
22
- }
23
- const [year, minor] = platformVersion.split('.');
24
- return Number(year) >= 2025 && Number(minor) >= 2;
25
- }
26
16
  function getSubtasks(task) {
27
17
  if ('subbuildStatuses' in task) {
28
18
  return task.subbuildStatuses;
@@ -1,5 +1,5 @@
1
1
  import { ComponentTypes, Component, GenericComponentConfig, PublicAppComponentConfig, PrivateAppComponentConfig, AppCardComponentConfig } from '../../types/Projects.js';
2
- import { IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types.js';
2
+ import { IntermediateRepresentationNode, IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types.js';
3
3
  import { AppIRNode } from '../../types/ProjectComponents.js';
4
4
  export declare const CONFIG_FILES: {
5
5
  [k in ComponentTypes]: string;
@@ -15,4 +15,4 @@ export declare function getProjectComponentTypes(components: Array<Component>):
15
15
  export declare function getComponentUid(component?: Component | null): string | null;
16
16
  export declare function componentIsApp(component?: Component | null): component is Component<PublicAppComponentConfig | PrivateAppComponentConfig>;
17
17
  export declare function componentIsPublicApp(component?: Component | null): component is Component<PublicAppComponentConfig>;
18
- export declare function isAppIRNode(component: IntermediateRepresentationNodeLocalDev): component is AppIRNode;
18
+ export declare function isAppIRNode(component: IntermediateRepresentationNodeLocalDev | IntermediateRepresentationNode): component is AppIRNode;
@@ -1,4 +1,5 @@
1
1
  import { FileResult } from 'tmp';
2
+ import { IntermediateRepresentation } from '@hubspot/project-parsing-lib';
2
3
  import { ProjectConfig } from '../../types/Projects.js';
3
4
  type ProjectUploadCallbackFunction<T> = (accountId: number, projectConfig: ProjectConfig, tempFile: FileResult, buildId: number) => Promise<T>;
4
5
  type ProjectUploadResult<T> = {
@@ -20,5 +21,5 @@ type HandleProjectUploadArg<T> = {
20
21
  export declare function handleProjectUpload<T>({ accountId, projectConfig, projectDir, callbackFunc, profile, uploadMessage, forceCreate, isUploadCommand, sendIR, skipValidation, }: HandleProjectUploadArg<T>): Promise<ProjectUploadResult<T>>;
21
22
  export declare function validateSourceDirectory(srcDir: string, projectConfig: ProjectConfig): void;
22
23
  export declare function validateNoHSMetaMismatch(srcDir: string, projectConfig: ProjectConfig): Promise<void>;
23
- export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<unknown>;
24
+ export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<IntermediateRepresentation | undefined>;
24
25
  export {};
@@ -12,7 +12,7 @@ import util from 'node:util';
12
12
  import { lib } from '../../lang/en.js';
13
13
  import { ensureProjectExists } from './ensureProjectExists.js';
14
14
  import { uiLogger } from '../ui/logger.js';
15
- import { useV3Api } from './buildAndDeploy.js';
15
+ import { useV3Api } from './platformVersion.js';
16
16
  import { EXIT_CODES } from '../enums/exitCodes.js';
17
17
  import ProjectValidationError from '../errors/ProjectValidationError.js';
18
18
  async function uploadProjectFiles(accountId, projectName, filePath, uploadMessage, platformVersion, intermediateRepresentation) {
@@ -133,4 +133,5 @@ export async function handleTranslate(projectDir, projectConfig, accountId, skip
133
133
  }
134
134
  throw e;
135
135
  }
136
+ return undefined;
136
137
  }
@@ -7,3 +7,4 @@ export declare function getProjectBuildDetailUrl(projectName: string, buildId: n
7
7
  export declare function getProjectDeployDetailUrl(projectName: string, deployId: number, accountId: number): string;
8
8
  export declare function getLocalDevUiUrl(accountId: number, showWelcomeScreen?: boolean): string;
9
9
  export declare function getAccountHomeUrl(accountId: number): string;
10
+ export declare function getAppAllowlistUrl(accountId: number, projectName: string, appUid: string): string;
@@ -41,3 +41,6 @@ export function getAccountHomeUrl(accountId) {
41
41
  const baseUrl = getHubSpotWebsiteOrigin(getEnv(accountId) === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD);
42
42
  return `${baseUrl}/home?portalId=${accountId}`;
43
43
  }
44
+ export function getAppAllowlistUrl(accountId, projectName, appUid) {
45
+ return `${getProjectHomeUrl(accountId)}/project/${projectName}/component/${appUid}/distribution?panel=static-token-allowlist`;
46
+ }
@@ -0,0 +1 @@
1
+ export {};