@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
@@ -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
  }
@@ -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
@@ -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 { IntermediateRepresentationNode, IntermediateRepresentationNodeLocalDev } from '@hubspot/project-parsing-lib/src/lib/types.js';
2
+ import { 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 | IntermediateRepresentationNode): component is AppIRNode;
18
+ export declare function isAppIRNode(component: IntermediateRepresentationNodeLocalDev): component is AppIRNode;
@@ -1,5 +1,4 @@
1
1
  import { FileResult } from 'tmp';
2
- import { IntermediateRepresentation } from '@hubspot/project-parsing-lib';
3
2
  import { ProjectConfig } from '../../types/Projects.js';
4
3
  type ProjectUploadCallbackFunction<T> = (accountId: number, projectConfig: ProjectConfig, tempFile: FileResult, buildId: number) => Promise<T>;
5
4
  type ProjectUploadResult<T> = {
@@ -21,5 +20,5 @@ type HandleProjectUploadArg<T> = {
21
20
  export declare function handleProjectUpload<T>({ accountId, projectConfig, projectDir, callbackFunc, profile, uploadMessage, forceCreate, isUploadCommand, sendIR, skipValidation, }: HandleProjectUploadArg<T>): Promise<ProjectUploadResult<T>>;
22
21
  export declare function validateSourceDirectory(srcDir: string, projectConfig: ProjectConfig): void;
23
22
  export declare function validateNoHSMetaMismatch(srcDir: string, projectConfig: ProjectConfig): Promise<void>;
24
- export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<IntermediateRepresentation | undefined>;
23
+ export declare function handleTranslate(projectDir: string, projectConfig: ProjectConfig, accountId: number, skipValidation: boolean, profile: string | undefined): Promise<unknown>;
25
24
  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,5 +133,4 @@ export async function handleTranslate(projectDir, projectConfig, accountId, skip
133
133
  }
134
134
  throw e;
135
135
  }
136
- return undefined;
137
136
  }
@@ -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 {};
@@ -0,0 +1,143 @@
1
+ import { Separator } from '@inquirer/prompts';
2
+ import { projectAddPromptV3 } from '../projectAddPrompt.js';
3
+ import { promptUser } from '../promptUtils.js';
4
+ vi.mock('../promptUtils');
5
+ const mockedPromptUser = vi.mocked(promptUser);
6
+ describe('lib/prompts/projectAddPrompt', () => {
7
+ const mockComponentTemplate = {
8
+ label: 'Test Module',
9
+ path: 'test-module',
10
+ type: 'module',
11
+ supportedAuthTypes: ['oauth'],
12
+ supportedDistributions: ['private'],
13
+ };
14
+ const mockComponentTemplateWithCliSelector = {
15
+ label: 'Workflow Action Tool',
16
+ path: 'workflow-action-tool',
17
+ type: 'workflow-action',
18
+ cliSelector: 'workflow-action-tool',
19
+ supportedAuthTypes: ['oauth'],
20
+ supportedDistributions: ['private'],
21
+ };
22
+ describe('projectAddPromptV3()', () => {
23
+ beforeEach(() => {
24
+ // Mock returns empty result, logic will use selectedComponents when selectedFeatures provided
25
+ mockedPromptUser.mockResolvedValue({});
26
+ });
27
+ it('should select component based on cliSelector when provided', async () => {
28
+ const templateChoice = {
29
+ name: 'Workflow Action Tool',
30
+ value: mockComponentTemplateWithCliSelector,
31
+ };
32
+ const components = [templateChoice];
33
+ const selectedFeatures = ['workflow-action-tool'];
34
+ const result = await projectAddPromptV3(components, selectedFeatures);
35
+ expect(result.componentTemplate).toEqual([
36
+ mockComponentTemplateWithCliSelector,
37
+ ]);
38
+ expect(mockedPromptUser).toHaveBeenCalledWith([
39
+ expect.objectContaining({
40
+ name: 'componentTemplate',
41
+ when: false, // selectedFeatures provided, so skip prompt
42
+ }),
43
+ ]);
44
+ });
45
+ it('should select component based on type when cliSelector not provided', async () => {
46
+ const templateChoice = {
47
+ name: 'Test Module',
48
+ value: mockComponentTemplate,
49
+ };
50
+ const components = [templateChoice];
51
+ const selectedFeatures = ['module'];
52
+ const result = await projectAddPromptV3(components, selectedFeatures);
53
+ expect(result.componentTemplate).toEqual([mockComponentTemplate]);
54
+ expect(mockedPromptUser).toHaveBeenCalledWith([
55
+ expect.objectContaining({
56
+ name: 'componentTemplate',
57
+ when: false, // selectedFeatures provided and selectedComponents found
58
+ }),
59
+ ]);
60
+ });
61
+ it('should prefer cliSelector over type when both are available', async () => {
62
+ const templateChoice = {
63
+ name: 'Workflow Action Tool',
64
+ value: mockComponentTemplateWithCliSelector,
65
+ };
66
+ const components = [templateChoice];
67
+ const selectedFeatures = ['workflow-action-tool']; // matches cliSelector
68
+ const result = await projectAddPromptV3(components, selectedFeatures);
69
+ expect(result.componentTemplate).toEqual([
70
+ mockComponentTemplateWithCliSelector,
71
+ ]);
72
+ });
73
+ it('should not select component when neither cliSelector nor type matches', async () => {
74
+ const templateChoice = {
75
+ name: 'Test Module',
76
+ value: mockComponentTemplate,
77
+ };
78
+ const components = [templateChoice];
79
+ const selectedFeatures = ['non-matching-feature'];
80
+ mockedPromptUser.mockResolvedValue({ componentTemplate: [] });
81
+ const result = await projectAddPromptV3(components, selectedFeatures);
82
+ expect(result.componentTemplate).toEqual([]);
83
+ });
84
+ it('should throw error when selected feature component is disabled', async () => {
85
+ const disabledTemplateChoice = {
86
+ name: 'Disabled Component',
87
+ value: mockComponentTemplateWithCliSelector,
88
+ disabled: 'Component is disabled for testing',
89
+ };
90
+ const components = [disabledTemplateChoice];
91
+ const selectedFeatures = ['workflow-action-tool'];
92
+ await expect(projectAddPromptV3(components, selectedFeatures)).rejects.toThrow(/Cannot.*feature.*workflow-action/);
93
+ });
94
+ it('should handle multiple components with mixed cliSelector availability', async () => {
95
+ const choice1 = {
96
+ name: 'Test Module',
97
+ value: mockComponentTemplate,
98
+ };
99
+ const choice2 = {
100
+ name: 'Workflow Action Tool',
101
+ value: mockComponentTemplateWithCliSelector,
102
+ };
103
+ const components = [choice1, choice2];
104
+ const selectedFeatures = ['module', 'workflow-action-tool'];
105
+ const result = await projectAddPromptV3(components, selectedFeatures);
106
+ expect(result.componentTemplate).toEqual([
107
+ mockComponentTemplate,
108
+ mockComponentTemplateWithCliSelector,
109
+ ]);
110
+ });
111
+ it('should skip Separator instances when processing components', async () => {
112
+ const separator = new Separator();
113
+ const templateChoice = {
114
+ name: 'Test Module',
115
+ value: mockComponentTemplate,
116
+ };
117
+ const components = [separator, templateChoice];
118
+ const selectedFeatures = ['module'];
119
+ const result = await projectAddPromptV3(components, selectedFeatures);
120
+ expect(result.componentTemplate).toEqual([mockComponentTemplate]);
121
+ });
122
+ it('should prompt user when no selectedFeatures provided', async () => {
123
+ const templateChoice = {
124
+ name: 'Test Module',
125
+ value: mockComponentTemplate,
126
+ };
127
+ const components = [templateChoice];
128
+ const selectedFeatures = undefined;
129
+ mockedPromptUser.mockResolvedValue({
130
+ componentTemplate: [mockComponentTemplate],
131
+ });
132
+ const result = await projectAddPromptV3(components, selectedFeatures);
133
+ expect(mockedPromptUser).toHaveBeenCalledWith([
134
+ expect.objectContaining({
135
+ name: 'componentTemplate',
136
+ type: 'checkbox',
137
+ choices: components,
138
+ }),
139
+ ]);
140
+ expect(result.componentTemplate).toEqual([mockComponentTemplate]);
141
+ });
142
+ });
143
+ });