@hubspot/cli 7.10.0 → 7.11.0-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 (211) hide show
  1. package/bin/cli.js +5 -4
  2. package/commands/__tests__/getStarted.test.js +10 -0
  3. package/commands/__tests__/project.test.js +3 -0
  4. package/commands/account/__tests__/rename.test.js +10 -3
  5. package/commands/account/auth.js +10 -14
  6. package/commands/account/clean.js +11 -19
  7. package/commands/account/createOverride.js +15 -11
  8. package/commands/account/info.js +8 -5
  9. package/commands/account/list.js +15 -19
  10. package/commands/account/remove.js +23 -22
  11. package/commands/account/removeOverride.js +6 -6
  12. package/commands/account/rename.js +2 -2
  13. package/commands/account/use.js +19 -8
  14. package/commands/app/__tests__/migrate.test.js +8 -4
  15. package/commands/app/migrate.js +2 -2
  16. package/commands/auth.js +18 -14
  17. package/commands/config/migrate.js +5 -5
  18. package/commands/customObject/createSchema.js +2 -3
  19. package/commands/customObject/updateSchema.js +2 -3
  20. package/commands/getStarted.js +2 -3
  21. package/commands/hubdb/__tests__/list.test.js +1 -0
  22. package/commands/hubdb/list.js +2 -2
  23. package/commands/init.js +36 -32
  24. package/commands/project/__tests__/deploy.test.js +15 -10
  25. package/commands/project/__tests__/devUnifiedFlow.test.js +6 -4
  26. package/commands/project/__tests__/lint.test.js +709 -0
  27. package/commands/project/__tests__/logs.test.js +4 -0
  28. package/commands/project/__tests__/validate.test.js +2 -2
  29. package/commands/project/cloneApp.js +2 -2
  30. package/commands/project/create.js +20 -14
  31. package/commands/project/deploy.js +2 -2
  32. package/commands/project/dev/deprecatedFlow.js +4 -5
  33. package/commands/project/dev/index.js +6 -3
  34. package/commands/project/dev/unifiedFlow.js +11 -6
  35. package/commands/project/lint.d.ts +6 -0
  36. package/commands/project/lint.js +178 -0
  37. package/commands/project/logs.js +2 -3
  38. package/commands/project/migrate.js +4 -13
  39. package/commands/project/profile/add.js +6 -7
  40. package/commands/project/profile/delete.js +2 -2
  41. package/commands/project/upload.js +2 -2
  42. package/commands/project/validate.js +2 -2
  43. package/commands/project.js +2 -0
  44. package/commands/sandbox/__tests__/create.test.js +14 -5
  45. package/commands/sandbox/create.js +4 -5
  46. package/commands/sandbox/delete.js +23 -20
  47. package/commands/testAccount/create.js +2 -2
  48. package/commands/testAccount/delete.js +9 -8
  49. package/lang/en.d.ts +53 -12
  50. package/lang/en.js +63 -16
  51. package/lib/__tests__/buildAccount.test.js +22 -30
  52. package/lib/__tests__/commonOpts.test.js +9 -13
  53. package/lib/__tests__/developerTestAccounts.test.js +29 -17
  54. package/lib/__tests__/importData.test.js +20 -10
  55. package/lib/__tests__/oauth.test.js +19 -8
  56. package/lib/__tests__/sandboxSync.test.js +33 -11
  57. package/lib/__tests__/sandboxes.test.js +30 -19
  58. package/lib/__tests__/usageTracking.test.js +10 -10
  59. package/lib/__tests__/validation.test.js +32 -32
  60. package/lib/accountTypes.d.ts +9 -9
  61. package/lib/accountTypes.js +2 -4
  62. package/lib/app/__tests__/migrate.test.js +15 -0
  63. package/lib/app/__tests__/migrate_legacy.test.js +9 -0
  64. package/lib/app/migrate_legacy.d.ts +2 -2
  65. package/lib/buildAccount.d.ts +4 -4
  66. package/lib/buildAccount.js +7 -14
  67. package/lib/commonOpts.js +3 -3
  68. package/lib/configMigrate.d.ts +2 -2
  69. package/lib/configMigrate.js +42 -18
  70. package/lib/configOptions.js +3 -2
  71. package/lib/developerTestAccounts.d.ts +3 -3
  72. package/lib/developerTestAccounts.js +4 -7
  73. package/lib/doctor/DiagnosticInfoBuilder.d.ts +1 -1
  74. package/lib/doctor/DiagnosticInfoBuilder.js +9 -6
  75. package/lib/doctor/Doctor.js +4 -3
  76. package/lib/doctor/__tests__/Diagnosis.test.js +4 -3
  77. package/lib/doctor/__tests__/DiagnosticInfoBuilder.test.js +17 -9
  78. package/lib/doctor/__tests__/Doctor.test.js +14 -0
  79. package/lib/errorHandlers/index.js +8 -3
  80. package/lib/importData.js +8 -7
  81. package/lib/links.js +5 -5
  82. package/lib/middleware/{__test__ → __tests__}/commandTargetingUtils.test.js +3 -3
  83. package/lib/middleware/{__test__ → __tests__}/configMiddleware.test.js +23 -22
  84. package/lib/middleware/{__test__ → __tests__}/gitMiddleware.test.js +9 -7
  85. package/lib/middleware/autoUpdateMiddleware.js +34 -23
  86. package/lib/middleware/commandTargetingUtils.js +3 -2
  87. package/lib/middleware/configMiddleware.d.ts +6 -1
  88. package/lib/middleware/configMiddleware.js +36 -15
  89. package/lib/middleware/fireAlarmMiddleware.js +4 -15
  90. package/lib/middleware/gitMiddleware.js +8 -4
  91. package/lib/oauth.d.ts +2 -2
  92. package/lib/oauth.js +8 -10
  93. package/lib/projects/__tests__/AppDevModeInterface.test.js +17 -6
  94. package/lib/projects/__tests__/DevServerManager.test.js +1 -0
  95. package/lib/projects/__tests__/LocalDevProcess.test.js +1 -0
  96. package/lib/projects/__tests__/components.test.js +2 -22
  97. package/lib/projects/__tests__/deploy.test.js +16 -13
  98. package/lib/projects/__tests__/uieLinting.test.js +640 -0
  99. package/lib/projects/add/__tests__/legacyAddComponent.test.js +1 -1
  100. package/lib/projects/add/__tests__/v2AddComponent.test.js +30 -4
  101. package/lib/projects/add/legacyAddComponent.js +1 -1
  102. package/lib/projects/add/v2AddComponent.js +16 -5
  103. package/lib/projects/components.d.ts +8 -1
  104. package/lib/projects/components.js +91 -8
  105. package/lib/projects/create/__tests__/v2.test.js +11 -0
  106. package/lib/projects/deploy.js +21 -8
  107. package/lib/projects/localDev/AppDevModeInterface.js +2 -2
  108. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +11 -3
  109. package/lib/projects/localDev/LocalDevLogger.js +4 -4
  110. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -3
  111. package/lib/projects/localDev/helpers/account.d.ts +10 -10
  112. package/lib/projects/localDev/helpers/account.js +6 -11
  113. package/lib/projects/localDev/helpers/process.js +5 -3
  114. package/lib/projects/uieLinting.d.ts +33 -0
  115. package/lib/projects/uieLinting.js +222 -0
  116. package/lib/projects/urls.js +5 -6
  117. package/lib/prompts/__tests__/downloadProjectPrompt.test.js +7 -5
  118. package/lib/prompts/accountNamePrompt.js +3 -3
  119. package/lib/prompts/accountsPrompt.d.ts +1 -1
  120. package/lib/prompts/accountsPrompt.js +6 -7
  121. package/lib/prompts/confirmImportDataPrompt.js +2 -2
  122. package/lib/prompts/downloadProjectPrompt.d.ts +1 -0
  123. package/lib/prompts/downloadProjectPrompt.js +5 -2
  124. package/lib/prompts/importDataTestAccountSelectPrompt.js +4 -5
  125. package/lib/prompts/personalAccessKeyPrompt.js +2 -2
  126. package/lib/prompts/projectDevTargetAccountPrompt.d.ts +3 -3
  127. package/lib/prompts/projectDevTargetAccountPrompt.js +5 -7
  128. package/lib/prompts/sandboxesPrompt.js +7 -8
  129. package/lib/prompts/setAsDefaultAccountPrompt.js +7 -6
  130. package/lib/sandboxSync.d.ts +2 -2
  131. package/lib/sandboxSync.js +3 -9
  132. package/lib/sandboxes.d.ts +4 -4
  133. package/lib/sandboxes.js +6 -11
  134. package/lib/serverlessLogs.js +2 -2
  135. package/lib/theme/__tests__/migrate.test.js +15 -0
  136. package/lib/ui/SpinniesManager.d.ts +5 -7
  137. package/lib/ui/SpinniesManager.js +9 -12
  138. package/lib/ui/__tests__/SpinniesManager.test.d.ts +1 -0
  139. package/lib/ui/__tests__/SpinniesManager.test.js +489 -0
  140. package/lib/ui/index.js +6 -3
  141. package/lib/usageTracking.js +15 -8
  142. package/lib/validation.js +13 -11
  143. package/mcp-server/tools/cms/HsCreateFunctionTool.js +4 -2
  144. package/mcp-server/tools/cms/HsCreateModuleTool.js +4 -2
  145. package/mcp-server/tools/cms/HsCreateTemplateTool.js +4 -2
  146. package/mcp-server/tools/cms/HsFunctionLogsTool.js +4 -2
  147. package/mcp-server/tools/cms/HsListFunctionsTool.js +3 -1
  148. package/mcp-server/tools/cms/HsListTool.js +3 -1
  149. package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -0
  150. package/mcp-server/tools/index.js +4 -0
  151. package/mcp-server/tools/project/AddFeatureToProjectTool.js +4 -2
  152. package/mcp-server/tools/project/CreateProjectTool.js +4 -2
  153. package/mcp-server/tools/project/CreateTestAccountTool.js +17 -7
  154. package/mcp-server/tools/project/DeployProjectTool.js +3 -1
  155. package/mcp-server/tools/project/DocFetchTool.js +6 -4
  156. package/mcp-server/tools/project/DocsSearchTool.d.ts +1 -1
  157. package/mcp-server/tools/project/DocsSearchTool.js +10 -8
  158. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.d.ts +1 -1
  159. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +9 -7
  160. package/mcp-server/tools/project/GetApplicationInfoTool.js +8 -6
  161. package/mcp-server/tools/project/GetBuildLogsTool.d.ts +26 -0
  162. package/mcp-server/tools/project/GetBuildLogsTool.js +125 -0
  163. package/mcp-server/tools/project/GetBuildStatusTool.d.ts +26 -0
  164. package/mcp-server/tools/project/GetBuildStatusTool.js +166 -0
  165. package/mcp-server/tools/project/GetConfigValuesTool.d.ts +1 -1
  166. package/mcp-server/tools/project/GetConfigValuesTool.js +9 -7
  167. package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +1 -1
  168. package/mcp-server/tools/project/GuidedWalkthroughTool.js +5 -3
  169. package/mcp-server/tools/project/UploadProjectTools.js +3 -1
  170. package/mcp-server/tools/project/ValidateProjectTool.js +4 -2
  171. package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +12 -2
  172. package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +5 -1
  173. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +23 -11
  174. package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +7 -5
  175. package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +7 -5
  176. package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.d.ts +1 -0
  177. package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.js +305 -0
  178. package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.d.ts +1 -0
  179. package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +240 -0
  180. package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +8 -6
  181. package/mcp-server/utils/__tests__/content.test.js +21 -20
  182. package/mcp-server/utils/__tests__/feedbackTracking.test.js +34 -28
  183. package/mcp-server/utils/config.d.ts +1 -0
  184. package/mcp-server/utils/config.js +10 -0
  185. package/mcp-server/utils/content.d.ts +1 -1
  186. package/mcp-server/utils/content.js +2 -2
  187. package/mcp-server/utils/feedbackTracking.d.ts +1 -1
  188. package/mcp-server/utils/feedbackTracking.js +3 -3
  189. package/mcp-server/utils/toolUsageTracking.js +4 -3
  190. package/package.json +9 -9
  191. package/ui/components/BoxWithTitle.d.ts +2 -1
  192. package/ui/components/BoxWithTitle.js +2 -2
  193. package/ui/components/StatusMessageBoxes.d.ts +5 -4
  194. package/ui/components/StatusMessageBoxes.js +8 -8
  195. package/lib/middleware/__test__/notificationsMiddleware.test.js +0 -8
  196. package/lib/middleware/notificationsMiddleware.d.ts +0 -1
  197. package/lib/middleware/notificationsMiddleware.js +0 -28
  198. package/lib/ui/boxen.d.ts +0 -5
  199. package/lib/ui/boxen.js +0 -26
  200. package/mcp-server/utils/__tests__/cliConfig.test.js +0 -110
  201. package/mcp-server/utils/cliConfig.d.ts +0 -1
  202. package/mcp-server/utils/cliConfig.js +0 -12
  203. /package/{lib/middleware/__test__/commandTargetingUtils.test.d.ts → commands/project/__tests__/lint.test.d.ts} +0 -0
  204. /package/lib/middleware/{__test__/configMiddleware.test.d.ts → __tests__/commandTargetingUtils.test.d.ts} +0 -0
  205. /package/lib/middleware/{__test__/gitMiddleware.test.d.ts → __tests__/configMiddleware.test.d.ts} +0 -0
  206. /package/lib/middleware/{__test__/notificationsMiddleware.test.d.ts → __tests__/gitMiddleware.test.d.ts} +0 -0
  207. /package/lib/middleware/{__test__ → __tests__}/requestMiddleware.test.d.ts +0 -0
  208. /package/lib/middleware/{__test__ → __tests__}/requestMiddleware.test.js +0 -0
  209. /package/lib/middleware/{__test__ → __tests__}/yargsChecksMiddleware.test.d.ts +0 -0
  210. /package/lib/middleware/{__test__ → __tests__}/yargsChecksMiddleware.test.js +0 -0
  211. /package/{mcp-server/utils/__tests__/cliConfig.test.d.ts → lib/projects/__tests__/uieLinting.test.d.ts} +0 -0
@@ -1,8 +1,10 @@
1
- import { getDeprecatedConfig, getGlobalConfig, getConfigPath, migrateConfig, mergeConfigProperties, mergeExistingConfigs, } from '@hubspot/local-dev-lib/config/migrate';
1
+ import { getConfigAtPath, migrateConfigAtPath, mergeConfigProperties, mergeConfigAccounts, archiveConfigAtPath, } from '@hubspot/local-dev-lib/config/migrate';
2
2
  import { ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME } from '@hubspot/local-dev-lib/constants/config';
3
3
  import { promptUser } from './prompts/promptUtils.js';
4
4
  import { lib } from '../lang/en.js';
5
5
  import { uiLogger } from './ui/logger.js';
6
+ import { getConfig, getLocalConfigFilePathIfExists, } from '@hubspot/local-dev-lib/config';
7
+ import { debugError } from './errorHandlers/index.js';
6
8
  async function promptRenameOrOmitAccount(accountName, accountId) {
7
9
  const { shouldRename } = await promptUser({
8
10
  name: 'shouldRename',
@@ -24,7 +26,7 @@ async function promptNewAccountName(account, globalConfig, renamedAccounts) {
24
26
  if (value === account.name) {
25
27
  return lib.configMigrate.handleAccountNameConflicts.errors.sameName;
26
28
  }
27
- const existingAccount = globalConfig.accounts?.some(acc => acc.name === value);
29
+ const existingAccount = globalConfig.accounts.some((acc) => acc.name === value);
28
30
  const renamedAccount = renamedAccounts.some(acc => acc.name === value);
29
31
  if (existingAccount || renamedAccount) {
30
32
  return lib.configMigrate.handleAccountNameConflicts.errors.nameAlreadyInConfig(value);
@@ -34,9 +36,10 @@ async function promptNewAccountName(account, globalConfig, renamedAccounts) {
34
36
  });
35
37
  return newAccountName;
36
38
  }
37
- export async function handleMigration(deprecatedConfigPath, hideWarning) {
39
+ export async function handleMigration(hideWarning) {
40
+ const deprecatedConfigPath = process.env.HUBSPOT_CONFIG_PATH || getLocalConfigFilePathIfExists();
38
41
  if (!hideWarning) {
39
- uiLogger.warn(lib.configMigrate.deprecatedConfigWarning(deprecatedConfigPath || getConfigPath(undefined, false)));
42
+ uiLogger.warn(lib.configMigrate.deprecatedConfigWarning(deprecatedConfigPath || ''));
40
43
  uiLogger.log('');
41
44
  }
42
45
  uiLogger.log(lib.configMigrate.handleMigration.description(ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME));
@@ -49,13 +52,20 @@ export async function handleMigration(deprecatedConfigPath, hideWarning) {
49
52
  if (!shouldMigrateConfig) {
50
53
  return false;
51
54
  }
52
- const deprecatedConfig = getDeprecatedConfig(deprecatedConfigPath);
53
- migrateConfig(deprecatedConfig);
55
+ migrateConfigAtPath(deprecatedConfigPath || '');
56
+ try {
57
+ archiveConfigAtPath(deprecatedConfigPath);
58
+ }
59
+ catch (error) {
60
+ debugError(error);
61
+ uiLogger.error(lib.configMigrate.errors.archive(deprecatedConfigPath));
62
+ return true;
63
+ }
54
64
  uiLogger.success(lib.configMigrate.handleMigration.success);
55
65
  return true;
56
66
  }
57
67
  async function handleMergeConfigProperties(globalConfig, deprecatedConfig, force) {
58
- const { initialConfig, conflicts, } = mergeConfigProperties(globalConfig, deprecatedConfig, force);
68
+ const { configWithMergedProperties, conflicts, } = mergeConfigProperties(globalConfig, deprecatedConfig, force);
59
69
  if (conflicts.length > 0) {
60
70
  const properties = conflicts.map(c => c.property);
61
71
  const propertyList = properties.length <= 2
@@ -68,15 +78,15 @@ async function handleMergeConfigProperties(globalConfig, deprecatedConfig, force
68
78
  const { shouldOverwrite } = await promptUser({
69
79
  name: 'shouldOverwrite',
70
80
  type: 'confirm',
71
- message: lib.configMigrate.handleMergeConfigProperties.mergeConfigConflictPrompt(property, newValue.toString(), oldValue.toString()),
81
+ message: lib.configMigrate.handleMergeConfigProperties.mergeConfigConflictPrompt(property, newValue.toString(), oldValue?.toString() || ''),
72
82
  });
73
83
  if (shouldOverwrite) {
74
84
  // @ts-expect-error Cannot reconcile CLIConfig_NEW and CLIConfig_DEPRECATED
75
- initialConfig[property] = oldValue;
85
+ configWithMergedProperties[property] = oldValue;
76
86
  }
77
87
  }
78
88
  }
79
- return initialConfig;
89
+ return configWithMergedProperties;
80
90
  }
81
91
  async function handleAccountNameConflicts(globalConfig, deprecatedConfig, force) {
82
92
  if (!deprecatedConfig.portals?.length || !globalConfig.accounts?.length) {
@@ -84,7 +94,7 @@ async function handleAccountNameConflicts(globalConfig, deprecatedConfig, force)
84
94
  }
85
95
  const accountsWithConflictsToRemove = new Set();
86
96
  const renamedAccounts = [];
87
- const accountsNotYetInGlobal = deprecatedConfig.portals.filter(portal => portal.portalId &&
97
+ const accountsNotYetInGlobal = (deprecatedConfig.portals || []).filter(portal => portal.portalId &&
88
98
  !globalConfig.accounts?.some(acc => acc.accountId === portal.portalId));
89
99
  const accountsWithConflicts = accountsNotYetInGlobal.filter(localAccount => globalConfig.accounts?.some(globalAccount => globalAccount.name === localAccount.name));
90
100
  if (accountsWithConflicts.length > 0) {
@@ -120,12 +130,13 @@ async function handleAccountNameConflicts(globalConfig, deprecatedConfig, force)
120
130
  }
121
131
  deprecatedConfig.portals.push(...renamedAccounts);
122
132
  }
123
- const cleanedPortals = deprecatedConfig.portals.filter(portal => !accountsWithConflictsToRemove.has(portal));
133
+ const cleanedPortals = (deprecatedConfig.portals || []).filter(portal => !accountsWithConflictsToRemove.has(portal));
124
134
  return { ...deprecatedConfig, portals: cleanedPortals };
125
135
  }
126
- export async function handleMerge(deprecatedConfigPath, force, hideWarning) {
136
+ export async function handleMerge(force, hideWarning) {
137
+ const deprecatedConfigPath = process.env.HUBSPOT_CONFIG_PATH || getLocalConfigFilePathIfExists();
127
138
  if (!hideWarning) {
128
- uiLogger.warn(lib.configMigrate.deprecatedConfigWarning(deprecatedConfigPath || getConfigPath(undefined, false)));
139
+ uiLogger.warn(lib.configMigrate.deprecatedConfigWarning(deprecatedConfigPath || ''));
129
140
  uiLogger.log('');
130
141
  }
131
142
  uiLogger.log(lib.configMigrate.handleMerge.description(ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME));
@@ -140,19 +151,32 @@ export async function handleMerge(deprecatedConfigPath, force, hideWarning) {
140
151
  return true; // exit with "true" so the user is shown a success message instead of an error
141
152
  }
142
153
  }
143
- const deprecatedConfig = getDeprecatedConfig(deprecatedConfigPath);
144
- const globalConfig = getGlobalConfig();
145
- if (!deprecatedConfig || !globalConfig) {
154
+ let deprecatedConfig;
155
+ let globalConfig;
156
+ try {
157
+ deprecatedConfig = getConfigAtPath(deprecatedConfigPath || '');
158
+ globalConfig = getConfig();
159
+ }
160
+ catch (error) {
161
+ debugError(error);
146
162
  return true;
147
163
  }
148
164
  const mergedConfig = await handleMergeConfigProperties(globalConfig, deprecatedConfig, force);
149
165
  const cleanedDeprecatedConfig = await handleAccountNameConflicts(mergedConfig, deprecatedConfig, force);
150
- const { skippedAccountIds } = mergeExistingConfigs(mergedConfig, cleanedDeprecatedConfig);
166
+ const { skippedAccountIds } = mergeConfigAccounts(mergedConfig, cleanedDeprecatedConfig);
151
167
  if (skippedAccountIds.length > 0) {
152
168
  uiLogger.log('');
153
169
  uiLogger.log(lib.configMigrate.handleMerge.skippedExistingAccounts(skippedAccountIds));
154
170
  uiLogger.log('');
155
171
  }
172
+ try {
173
+ archiveConfigAtPath(deprecatedConfigPath);
174
+ }
175
+ catch (error) {
176
+ debugError(error);
177
+ uiLogger.error(lib.configMigrate.errors.archive(deprecatedConfigPath));
178
+ return true;
179
+ }
156
180
  uiLogger.success(lib.configMigrate.handleMerge.success);
157
181
  return true;
158
182
  }
@@ -1,4 +1,4 @@
1
- import { updateAllowUsageTracking, updateAllowAutoUpdates, updateDefaultCmsPublishMode, updateHttpTimeout, isConfigFlagEnabled, updateAutoOpenBrowser, } from '@hubspot/local-dev-lib/config';
1
+ import { updateAllowUsageTracking, updateAllowAutoUpdates, updateDefaultCmsPublishMode, updateHttpTimeout, updateAutoOpenBrowser, getConfig, } from '@hubspot/local-dev-lib/config';
2
2
  import { CMS_PUBLISH_MODE } from '@hubspot/local-dev-lib/constants/files';
3
3
  import { commaSeparatedValues } from '@hubspot/local-dev-lib/text';
4
4
  import { trackCommandUsage } from './usageTracking.js';
@@ -110,5 +110,6 @@ export async function setAutoOpenBrowser({ accountId, autoOpenBrowser, }) {
110
110
  : lib.configOptions.setAutoOpenBrowser.disabled);
111
111
  }
112
112
  export function isAutoOpenBrowserEnabled() {
113
- return isConfigFlagEnabled('autoOpenBrowser', true);
113
+ const config = getConfig();
114
+ return config?.autoOpenBrowser !== false; // Default to true
114
115
  }
@@ -1,6 +1,6 @@
1
- import { CLIAccount } from '@hubspot/local-dev-lib/types/Accounts';
1
+ import { HubSpotConfigAccount } from '@hubspot/local-dev-lib/types/Accounts';
2
2
  import { FetchDeveloperTestAccountsResponse } from '@hubspot/local-dev-lib/types/developerTestAccounts.js';
3
3
  import { Environment } from '@hubspot/local-dev-lib/types/Config';
4
- export declare function getHasDevTestAccounts(appDeveloperAccountConfig: CLIAccount): boolean;
5
- export declare function validateDevTestAccountUsageLimits(accountConfig: CLIAccount): Promise<FetchDeveloperTestAccountsResponse | null>;
4
+ export declare function getHasDevTestAccounts(appDeveloperAccountConfig: HubSpotConfigAccount): boolean;
5
+ export declare function validateDevTestAccountUsageLimits(accountConfig: HubSpotConfigAccount): Promise<FetchDeveloperTestAccountsResponse | null>;
6
6
  export declare function handleDeveloperTestAccountCreateError(err: unknown, accountId: number, env: Environment, portalLimit: number): never;
@@ -1,6 +1,5 @@
1
1
  import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
2
- import { getAccountId, getConfigAccounts } from '@hubspot/local-dev-lib/config';
3
- import { getAccountIdentifier } from '@hubspot/local-dev-lib/config/getAccountIdentifier';
2
+ import { getAllConfigAccounts } from '@hubspot/local-dev-lib/config';
4
3
  import { fetchDeveloperTestAccounts } from '@hubspot/local-dev-lib/api/developerTestAccounts';
5
4
  import { isMissingScopeError, isSpecifiedError, } from '@hubspot/local-dev-lib/errors/index';
6
5
  import { uiLogger } from './ui/logger.js';
@@ -9,9 +8,8 @@ import { lib } from '../lang/en.js';
9
8
  import { uiAccountDescription } from './ui/index.js';
10
9
  import { logError } from './errorHandlers/index.js';
11
10
  export function getHasDevTestAccounts(appDeveloperAccountConfig) {
12
- const id = getAccountIdentifier(appDeveloperAccountConfig);
13
- const parentPortalId = getAccountId(id);
14
- const accountsList = getConfigAccounts();
11
+ const parentPortalId = appDeveloperAccountConfig.accountId;
12
+ const accountsList = getAllConfigAccounts();
15
13
  if (!accountsList) {
16
14
  return false;
17
15
  }
@@ -25,8 +23,7 @@ export function getHasDevTestAccounts(appDeveloperAccountConfig) {
25
23
  return false;
26
24
  }
27
25
  export async function validateDevTestAccountUsageLimits(accountConfig) {
28
- const id = getAccountIdentifier(accountConfig);
29
- const accountId = getAccountId(id);
26
+ const accountId = accountConfig.accountId;
30
27
  if (!accountId) {
31
28
  return null;
32
29
  }
@@ -44,7 +44,7 @@ export interface DiagnosticInfo extends FilesInfo {
44
44
  warningCount?: number;
45
45
  }
46
46
  export declare class DiagnosticInfoBuilder {
47
- accountId: number | null;
47
+ accountId: number | undefined;
48
48
  readonly configSettings: {
49
49
  [key: string]: unknown;
50
50
  };
@@ -3,8 +3,8 @@ import { fetchProject } from '@hubspot/local-dev-lib/api/projects';
3
3
  import path from 'path';
4
4
  import { pkg } from '../jsonLoader.js';
5
5
  import { uiLogger } from '../ui/logger.js';
6
- import { getAccountId, getDefaultAccountOverrideFilePath, isConfigFlagEnabled, } from '@hubspot/local-dev-lib/config';
7
- import { getAccountConfig, getConfigPath } from '@hubspot/local-dev-lib/config';
6
+ import { isConfigFlagEnabled, getConfigFilePath, getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
7
+ import { getDefaultAccountOverrideFilePath } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
8
8
  import { getAccessToken } from '@hubspot/local-dev-lib/personalAccessKey';
9
9
  import { walk } from '@hubspot/local-dev-lib/fs';
10
10
  import util from 'util';
@@ -33,15 +33,18 @@ export class DiagnosticInfoBuilder {
33
33
  files;
34
34
  processInfo;
35
35
  constructor(processInfo) {
36
- this.accountId = getAccountId();
37
- const accountConfig = getAccountConfig(this.accountId);
36
+ const accountConfig = getConfigDefaultAccountIfExists();
37
+ this.accountId = accountConfig?.accountId;
38
38
  this.configSettings = {
39
39
  httpUseLocalhost: isConfigFlagEnabled('httpUseLocalhost'),
40
40
  };
41
41
  this.env = accountConfig?.env;
42
42
  this.authType = accountConfig?.authType;
43
43
  this.accountType = accountConfig?.accountType;
44
- this.personalAccessKey = accountConfig?.personalAccessKey;
44
+ this.personalAccessKey =
45
+ accountConfig && 'personalAccessKey' in accountConfig
46
+ ? accountConfig.personalAccessKey
47
+ : undefined;
45
48
  this.processInfo = processInfo;
46
49
  }
47
50
  async generateDiagnosticInfo() {
@@ -58,7 +61,7 @@ export class DiagnosticInfoBuilder {
58
61
  platform,
59
62
  arch,
60
63
  path: mainModule?.path,
61
- config: getConfigPath(),
64
+ config: getConfigFilePath(),
62
65
  defaultAccountOverrideFile: getDefaultAccountOverrideFilePath(),
63
66
  configSettings: this.configSettings,
64
67
  versions: {
@@ -1,5 +1,6 @@
1
1
  import { uiLogger } from '../ui/logger.js';
2
- import { getAccountId, getCWDAccountOverride, } from '@hubspot/local-dev-lib/config';
2
+ import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
3
+ import { getDefaultAccountOverrideAccountId } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
3
4
  import SpinniesManager from '../ui/SpinniesManager.js';
4
5
  import { hasMissingPackages } from '../dependencyManagement.js';
5
6
  import { getLatestCliVersion } from '../npm.js';
@@ -25,7 +26,7 @@ export class Doctor {
25
26
  diagnosticInfoBuilder;
26
27
  constructor(diagnosticInfoBuilder = new DiagnosticInfoBuilder(process)) {
27
28
  SpinniesManager.init();
28
- this.accountId = getAccountId();
29
+ this.accountId = getConfigDefaultAccountIfExists()?.accountId ?? null;
29
30
  this.diagnosticInfoBuilder = diagnosticInfoBuilder;
30
31
  }
31
32
  async diagnose() {
@@ -88,7 +89,7 @@ export class Doctor {
88
89
  });
89
90
  this.diagnosis?.addDefaultAccountOverrideFileSection({
90
91
  type: 'warning',
91
- message: lib.doctor.defaultAccountOverrideFileChecks.overrideAccountId(getCWDAccountOverride()),
92
+ message: lib.doctor.defaultAccountOverrideFileChecks.overrideAccountId(getDefaultAccountOverrideAccountId()),
92
93
  });
93
94
  }
94
95
  }
@@ -1,8 +1,8 @@
1
1
  vi.mock('@hubspot/local-dev-lib/config');
2
2
  import { Diagnosis } from '../Diagnosis.js';
3
- import { getAccountConfig as __getAccountConfig } from '@hubspot/local-dev-lib/config';
3
+ import { getConfigAccountIfExists as __getConfigAccountIfExists } from '@hubspot/local-dev-lib/config';
4
4
  import stripAnsi from 'strip-ansi';
5
- const getAccountConfig = __getAccountConfig;
5
+ const getConfigAccountIfExists = __getConfigAccountIfExists;
6
6
  describe('lib/doctor/Diagnosis', () => {
7
7
  const diagnosticInfo = {
8
8
  account: {},
@@ -31,7 +31,8 @@ describe('lib/doctor/Diagnosis', () => {
31
31
  };
32
32
  const accountId = 123456;
33
33
  beforeEach(() => {
34
- getAccountConfig.mockReturnValue({
34
+ getConfigAccountIfExists.mockReturnValue({
35
+ accountId,
35
36
  accountType: 'STANDARD',
36
37
  name: 'Standard Account',
37
38
  });
@@ -2,6 +2,7 @@ import util from 'util';
2
2
  import { vi } from 'vitest';
3
3
  vi.mock('@hubspot/local-dev-lib/fs');
4
4
  vi.mock('@hubspot/local-dev-lib/config');
5
+ vi.mock('@hubspot/local-dev-lib/config/defaultAccountOverride');
5
6
  vi.mock('@hubspot/local-dev-lib/personalAccessKey');
6
7
  vi.mock('../../projects/config');
7
8
  vi.mock('@hubspot/local-dev-lib/api/projects');
@@ -16,17 +17,19 @@ vi.mock('../../jsonLoader.js', () => {
16
17
  };
17
18
  });
18
19
  import { DiagnosticInfoBuilder, } from '../DiagnosticInfoBuilder.js';
19
- import { getAccountId as _getAccountId, getAccountConfig as _getAccountConfig, getConfigPath as _getConfigPath, getDefaultAccountOverrideFilePath as _getDefaultAccountOverrideFilePath, isConfigFlagEnabled as _isConfigFlagEnabled, } from '@hubspot/local-dev-lib/config';
20
+ import { getConfigAccountIfExists as _getConfigAccountIfExists, getConfigAccountById as _getConfigAccountById, getConfigFilePath as _getConfigFilePath, isConfigFlagEnabled as _isConfigFlagEnabled, getConfigDefaultAccountIfExists as _getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
21
+ import { getDefaultAccountOverrideFilePath as _getDefaultAccountOverrideFilePath } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
20
22
  import { getAccessToken as _getAccessToken } from '@hubspot/local-dev-lib/personalAccessKey';
21
23
  import { walk as _walk } from '@hubspot/local-dev-lib/fs';
22
24
  import { getProjectConfig as _getProjectConfig } from '../../projects/config.js';
23
25
  import { fetchProject as _fetchProject } from '@hubspot/local-dev-lib/api/projects';
24
26
  const walk = _walk;
25
27
  const getAccessToken = _getAccessToken;
26
- const getAccountConfig = _getAccountConfig;
27
- const getConfigPath = _getConfigPath;
28
+ const getConfigAccountById = _getConfigAccountById;
29
+ const getConfigAccountIfExists = _getConfigAccountIfExists;
30
+ const getConfigDefaultAccountIfExists = _getConfigDefaultAccountIfExists;
31
+ const getConfigFilePath = _getConfigFilePath;
28
32
  const getDefaultAccountOverrideFilePath = _getDefaultAccountOverrideFilePath;
29
- const getAccountId = _getAccountId;
30
33
  const getProjectConfig = _getProjectConfig;
31
34
  const isConfigFlagEnabled = _isConfigFlagEnabled;
32
35
  const fetchProject = _fetchProject;
@@ -36,6 +39,8 @@ util.promisify = utilPromisify;
36
39
  describe('lib/doctor/DiagnosticInfo', () => {
37
40
  const accountId = 898989;
38
41
  const accountConfig = {
42
+ name: 'test-account',
43
+ accountId: accountId,
39
44
  env: 'prod',
40
45
  authType: 'personalaccesskey',
41
46
  accountType: 'STANDARD',
@@ -73,16 +78,19 @@ describe('lib/doctor/DiagnosticInfo', () => {
73
78
  const configPath = '/path/to/config';
74
79
  const defaultAccountOverrideFile = 'path/to/default/account/override/.hsaccount';
75
80
  beforeEach(() => {
76
- getAccountId.mockReturnValue(accountId);
77
- getAccountConfig.mockReturnValue(accountConfig);
81
+ getConfigAccountIfExists.mockReturnValue({
82
+ accountId,
83
+ name: 'test',
84
+ });
85
+ getConfigAccountById.mockReturnValue(accountConfig);
86
+ getConfigDefaultAccountIfExists.mockReturnValue(accountConfig);
78
87
  walk.mockResolvedValue(projectFiles);
79
88
  isConfigFlagEnabled.mockReturnValue(false);
80
89
  mockPromisifyImpl.mockResolvedValue(npmVersion);
81
90
  });
82
91
  it('should initialize the required state on creation', () => {
83
92
  const builder = new DiagnosticInfoBuilder(processInfo);
84
- expect(getAccountId).toHaveBeenCalledTimes(1);
85
- expect(getAccountConfig).toHaveBeenCalledTimes(1);
93
+ expect(getConfigDefaultAccountIfExists).toHaveBeenCalledTimes(1);
86
94
  expect(builder.accountId).toEqual(accountId);
87
95
  expect(builder.env).toEqual(accountConfig.env);
88
96
  expect(builder.authType).toEqual(accountConfig.authType);
@@ -131,7 +139,7 @@ describe('lib/doctor/DiagnosticInfo', () => {
131
139
  data: projectDetails,
132
140
  });
133
141
  getAccessToken.mockResolvedValue(accessToken);
134
- getConfigPath.mockReturnValue(configPath);
142
+ getConfigFilePath.mockReturnValue(configPath);
135
143
  getDefaultAccountOverrideFilePath.mockReturnValue(defaultAccountOverrideFile);
136
144
  });
137
145
  it('should gather the required data and generate the diagnostic', async () => {
@@ -6,6 +6,7 @@ import { HubSpotHttpError } from '@hubspot/local-dev-lib/models/HubSpotHttpError
6
6
  import { AxiosError } from 'axios';
7
7
  import { isSpecifiedError as _isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
8
8
  import { promisify as _promisify } from 'util';
9
+ import { getConfigDefaultAccount as _getConfigDefaultAccount, getConfigDefaultAccountIfExists as _getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
9
10
  vi.mock('../../ui/logger.js');
10
11
  vi.mock('../Diagnosis');
11
12
  vi.mock('../../ui/SpinniesManager');
@@ -15,6 +16,7 @@ vi.mock('../../npm');
15
16
  vi.mock('@hubspot/local-dev-lib/portManager');
16
17
  vi.mock('@hubspot/local-dev-lib/personalAccessKey');
17
18
  vi.mock('@hubspot/local-dev-lib/errors/index');
19
+ vi.mock('@hubspot/local-dev-lib/config');
18
20
  vi.mock('util');
19
21
  const hasMissingPackages = vi.mocked(_hasMissingPackages);
20
22
  const isPortManagerPortAvailable = vi.mocked(_isPortManagerPortAvailable);
@@ -23,6 +25,8 @@ const accessTokenForPersonalAccessKey = vi.mocked(_accessTokenForPersonalAccessK
23
25
  const authorizedScopesForPortalAndUser = vi.mocked(_authorizedScopesForPortalAndUser);
24
26
  const scopesOnAccessToken = vi.mocked(_scopesOnAccessToken);
25
27
  const isSpecifiedError = vi.mocked(_isSpecifiedError);
28
+ const getConfigDefaultAccount = vi.mocked(_getConfigDefaultAccount);
29
+ const getConfigDefaultAccountIfExists = vi.mocked(_getConfigDefaultAccountIfExists);
26
30
  describe('lib/doctor/Doctor', () => {
27
31
  let doctor;
28
32
  // @ts-ignore
@@ -57,6 +61,16 @@ describe('lib/doctor/Doctor', () => {
57
61
  },
58
62
  };
59
63
  beforeEach(() => {
64
+ // Mock config functions
65
+ const mockAccount = {
66
+ accountId: 123456,
67
+ accountType: 'STANDARD',
68
+ name: 'Test Account',
69
+ authType: 'personalaccesskey',
70
+ personalAccessKey: 'test-key',
71
+ };
72
+ getConfigDefaultAccount.mockReturnValue(mockAccount);
73
+ getConfigDefaultAccountIfExists.mockReturnValue(mockAccount);
60
74
  doctor = new Doctor({
61
75
  generateDiagnosticInfo: vi.fn().mockResolvedValue({
62
76
  ...diagnosticInfo,
@@ -57,9 +57,14 @@ export function debugError(error, context) {
57
57
  }
58
58
  else {
59
59
  uiLogger.debug(lib.errorHandlers.index.errorOccurred(String(error)));
60
- }
61
- if (error instanceof Error && error.cause && !isHubSpotHttpError(error)) {
62
- uiLogger.debug(lib.errorHandlers.index.errorCause(util.inspect(error.cause, false, null, true)));
60
+ if (error instanceof Error && error.cause) {
61
+ if (isHubSpotHttpError(error.cause)) {
62
+ uiLogger.debug(error.cause.toString());
63
+ }
64
+ else {
65
+ uiLogger.debug(lib.errorHandlers.index.errorCause(util.inspect(error.cause, false, null, true)));
66
+ }
67
+ }
63
68
  }
64
69
  if (context) {
65
70
  uiLogger.debug(lib.errorHandlers.index.errorContext(util.inspect(context, false, null, true)));
package/lib/importData.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getAccountConfig, getAccountId, getEnv, } from '@hubspot/local-dev-lib/config';
1
+ import { getConfigAccountById, getConfigAccountEnvironment, getConfigAccountIfExists, } from '@hubspot/local-dev-lib/config';
2
2
  import { createImport } from '@hubspot/local-dev-lib/api/crm';
3
3
  import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
4
4
  import { importDataTestAccountSelectPrompt } from './prompts/importDataTestAccountSelectPrompt.js';
@@ -7,7 +7,7 @@ import { isAppDeveloperAccount, isDeveloperTestAccount, isStandardAccount, } fro
7
7
  import { uiLogger } from './ui/logger.js';
8
8
  export async function handleImportData(targetAccountId, dataFileNames, importRequest) {
9
9
  try {
10
- const baseUrl = getHubSpotWebsiteOrigin(getEnv());
10
+ const baseUrl = getHubSpotWebsiteOrigin(getConfigAccountEnvironment(targetAccountId));
11
11
  const response = await createImport(targetAccountId, importRequest, dataFileNames);
12
12
  const importId = response.data.id;
13
13
  uiLogger.info(lib.importData.viewImportLink(baseUrl, targetAccountId, importId));
@@ -18,19 +18,20 @@ export async function handleImportData(targetAccountId, dataFileNames, importReq
18
18
  }
19
19
  }
20
20
  export async function handleTargetTestAccountSelectionFlow(derivedAccountId, userProvidedAccount) {
21
- let targetAccountId = null;
21
+ let targetAccountId;
22
+ let testAccount;
22
23
  if (userProvidedAccount) {
23
- targetAccountId = getAccountId(userProvidedAccount);
24
+ testAccount = getConfigAccountIfExists(userProvidedAccount);
25
+ targetAccountId = testAccount?.accountId;
24
26
  }
25
27
  // Only allow users to pass in test accounts
26
28
  if (targetAccountId) {
27
- const testAccount = getAccountConfig(targetAccountId);
28
- if (!testAccount || !isDeveloperTestAccount(testAccount)) {
29
+ if (testAccount && !isDeveloperTestAccount(testAccount)) {
29
30
  throw new Error(lib.importData.errors.notDeveloperTestAccount);
30
31
  }
31
32
  }
32
33
  else {
33
- const targetProjectAccountConfig = getAccountConfig(derivedAccountId);
34
+ const targetProjectAccountConfig = getConfigAccountById(derivedAccountId);
34
35
  if (!targetProjectAccountConfig) {
35
36
  throw new Error(lib.importData.errors.noAccountConfig(derivedAccountId));
36
37
  }
package/lib/links.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import open from 'open';
2
- import { getEnv } from '@hubspot/local-dev-lib/config';
3
- import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
2
+ import { getConfigAccountEnvironment } from '@hubspot/local-dev-lib/config';
4
3
  import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
4
+ import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
5
5
  import { uiLogger } from './ui/logger.js';
6
6
  import { getTableContents, getTableHeader } from './ui/table.js';
7
7
  const COMMON_SITE_LINKS = {
@@ -75,7 +75,7 @@ const COMMON_SITE_LINKS = {
75
75
  },
76
76
  };
77
77
  export function getSiteLinksAsArray(accountId) {
78
- const baseUrl = getHubSpotWebsiteOrigin(getEnv() === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD);
78
+ const baseUrl = getHubSpotWebsiteOrigin(getConfigAccountEnvironment(accountId));
79
79
  return Object.values(COMMON_SITE_LINKS)
80
80
  .sort((a, b) => (a.shortcut < b.shortcut ? -1 : 1))
81
81
  .map(l => ({ ...l, url: l.getUrl(accountId, baseUrl) }));
@@ -95,12 +95,12 @@ export function openLink(accountId, shortcut) {
95
95
  uiLogger.error(`We couldn't find a shortcut matching ${shortcut}. Type 'hs open list' to see a list of available shortcuts`);
96
96
  return;
97
97
  }
98
- const baseUrl = getHubSpotWebsiteOrigin(getEnv() === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD);
98
+ const baseUrl = getHubSpotWebsiteOrigin(getConfigAccountEnvironment(accountId));
99
99
  open(match.getUrl(accountId, baseUrl), { url: true });
100
100
  uiLogger.success(`We opened ${match.getUrl(accountId, baseUrl)} in your browser`);
101
101
  }
102
102
  export function getProductUpdatesUrl(rolloutId, accountId) {
103
- const baseUrl = getHubSpotWebsiteOrigin(getEnv() === 'qa' ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD);
103
+ const baseUrl = getHubSpotWebsiteOrigin(accountId ? getConfigAccountEnvironment(accountId) : ENVIRONMENTS.PROD);
104
104
  if (accountId) {
105
105
  return `${baseUrl}/product-updates/${accountId}/in-beta?rollout=${rolloutId}`;
106
106
  }
@@ -1,7 +1,7 @@
1
1
  import * as cliConfig from '@hubspot/local-dev-lib/config';
2
2
  import { isTargetedCommand, shouldLoadConfigForCommand, shouldRunAccountValidationForCommand, shouldRunConfigValidationForCommand, } from '../commandTargetingUtils.js';
3
3
  vi.mock('@hubspot/local-dev-lib/config');
4
- const configFileExistsSpy = vi.spyOn(cliConfig, 'configFileExists');
4
+ const globalConfigFileExistsSpy = vi.spyOn(cliConfig, 'globalConfigFileExists');
5
5
  const targetCommandMap = {
6
6
  init: true,
7
7
  account: {
@@ -56,12 +56,12 @@ describe('lib/middleware/commandTargetingUtils', () => {
56
56
  expect(result).toBe(false);
57
57
  });
58
58
  it('should return false when the user is trying to migrate the global config', () => {
59
- configFileExistsSpy.mockReturnValue(false);
59
+ globalConfigFileExistsSpy.mockReturnValue(false);
60
60
  const result = shouldLoadConfigForCommand(['config', 'migrate']);
61
61
  expect(result).toBe(false);
62
62
  });
63
63
  it('should return true when the global config file does exist', () => {
64
- configFileExistsSpy.mockReturnValue(true);
64
+ globalConfigFileExistsSpy.mockReturnValue(true);
65
65
  const result = shouldLoadConfigForCommand(['account', 'use']);
66
66
  expect(result).toBe(true);
67
67
  });
@@ -2,7 +2,7 @@ import { uiLogger } from '../../ui/logger.js';
2
2
  import * as cliConfig from '@hubspot/local-dev-lib/config';
3
3
  import * as validation from '../../validation.js';
4
4
  import { EXIT_CODES } from '../../enums/exitCodes.js';
5
- import { handleDeprecatedEnvVariables, injectAccountIdMiddleware, loadAndValidateConfigMiddleware, validateAccountOptions, } from '../configMiddleware.js';
5
+ import { handleDeprecatedEnvVariables, injectAccountIdMiddleware, validateConfigMiddleware, validateAccountOptions, } from '../configMiddleware.js';
6
6
  vi.mock('../../ui/logger.js', () => ({
7
7
  uiLogger: {
8
8
  error: vi.fn(),
@@ -12,10 +12,10 @@ vi.mock('../../ui/logger.js', () => ({
12
12
  vi.mock('@hubspot/local-dev-lib/config');
13
13
  vi.mock('../../validation');
14
14
  const validateAccountSpy = vi.spyOn(validation, 'validateAccount');
15
- const loadConfigSpy = vi.spyOn(cliConfig, 'loadConfig');
16
- const getAccountIdSpy = vi.spyOn(cliConfig, 'getAccountId');
15
+ const getConfigAccountIfExistsSpy = vi.spyOn(cliConfig, 'getConfigAccountIfExists');
16
+ const globalConfigFileExistsSpy = vi.spyOn(cliConfig, 'globalConfigFileExists');
17
17
  const configFileExistsSpy = vi.spyOn(cliConfig, 'configFileExists');
18
- const getConfigPathSpy = vi.spyOn(cliConfig, 'getConfigPath');
18
+ const getConfigFilePathSpy = vi.spyOn(cliConfig, 'getConfigFilePath');
19
19
  const validateConfigSpy = vi.spyOn(cliConfig, 'validateConfig');
20
20
  const processExitSpy = vi.spyOn(process, 'exit');
21
21
  describe('lib/middleware/configMiddleware', () => {
@@ -23,7 +23,7 @@ describe('lib/middleware/configMiddleware', () => {
23
23
  processExitSpy.mockImplementation(code => {
24
24
  throw new Error(`Process.exit called with code ${code}`);
25
25
  });
26
- getConfigPathSpy.mockReturnValue('/path/to/config');
26
+ getConfigFilePathSpy.mockReturnValue('/path/to/config');
27
27
  });
28
28
  describe('handleDeprecatedEnvVariables()', () => {
29
29
  it('should handle deprecated HUBSPOT_PORTAL_ID environment variable', () => {
@@ -76,11 +76,13 @@ describe('lib/middleware/configMiddleware', () => {
76
76
  await injectAccountIdMiddleware(argv);
77
77
  expect(argv.userProvidedAccount).toBeUndefined();
78
78
  expect(argv.derivedAccountId).toBe(123);
79
- expect(getAccountIdSpy).not.toHaveBeenCalled();
79
+ expect(getConfigAccountIfExistsSpy).not.toHaveBeenCalled();
80
80
  process.env = originalEnv;
81
81
  });
82
82
  it('should use getAccountId when useEnv is false', async () => {
83
- getAccountIdSpy.mockReturnValue(456);
83
+ getConfigAccountIfExistsSpy.mockReturnValue({
84
+ accountId: 456,
85
+ });
84
86
  const argv = {
85
87
  _: ['some-command'],
86
88
  account: 'test-account',
@@ -90,41 +92,40 @@ describe('lib/middleware/configMiddleware', () => {
90
92
  await injectAccountIdMiddleware(argv);
91
93
  expect(argv.userProvidedAccount).toBe('test-account');
92
94
  expect(argv.derivedAccountId).toBe(456);
93
- expect(getAccountIdSpy).toHaveBeenCalledWith('test-account');
95
+ expect(getConfigAccountIfExistsSpy).toHaveBeenCalledWith('test-account');
94
96
  });
95
97
  });
96
- describe('loadAndValidateConfigMiddleware()', () => {
97
- it('should exit with error when config file exists and --config flag is used', async () => {
98
+ describe('validateConfigMiddleware()', () => {
99
+ it('should allow using --config flag', async () => {
98
100
  configFileExistsSpy.mockReturnValue(true);
101
+ validateConfigSpy.mockReturnValue({ isValid: true, errors: [] });
99
102
  const argv = {
100
103
  _: ['some-command'],
101
104
  config: 'custom-config.json',
102
105
  $0: 'hs',
103
106
  };
104
- await expect(loadAndValidateConfigMiddleware(argv)).rejects.toThrow();
105
- expect(processExitSpy).toHaveBeenCalledWith(EXIT_CODES.ERROR);
106
- expect(uiLogger.error).toHaveBeenCalledWith('A configuration file already exists at /path/to/config. To specify a new configuration file, delete the existing one and try again.');
107
+ await validateConfigMiddleware(argv);
108
+ // Should not throw or exit - this is now allowed
109
+ expect(processExitSpy).not.toHaveBeenCalled();
110
+ expect(uiLogger.error).not.toHaveBeenCalled();
107
111
  });
108
- it('should load config and validate for non-init commands', async () => {
109
- configFileExistsSpy.mockReturnValue(false);
110
- loadConfigSpy.mockReturnValue({});
111
- validateConfigSpy.mockReturnValue(true);
112
+ it('should validate config for non-init commands', async () => {
113
+ globalConfigFileExistsSpy.mockReturnValue(true);
114
+ validateConfigSpy.mockReturnValue({ isValid: true, errors: [] });
112
115
  const argv = {
113
116
  _: ['some-command'],
114
117
  $0: 'hs',
115
118
  };
116
- await loadAndValidateConfigMiddleware(argv);
117
- expect(loadConfigSpy).toHaveBeenCalled();
119
+ await validateConfigMiddleware(argv);
118
120
  expect(validateConfigSpy).toHaveBeenCalled();
119
121
  });
120
122
  it('should skip validation for init command', async () => {
121
- configFileExistsSpy.mockReturnValue(false);
123
+ globalConfigFileExistsSpy.mockReturnValue(false);
122
124
  const argv = {
123
125
  _: ['init'],
124
126
  $0: 'hs',
125
127
  };
126
- await loadAndValidateConfigMiddleware(argv);
127
- expect(loadConfigSpy).not.toHaveBeenCalled();
128
+ await validateConfigMiddleware(argv);
128
129
  expect(validateConfigSpy).not.toHaveBeenCalled();
129
130
  });
130
131
  });