@hubspot/cli 7.11.8-experimental.0 → 8.0.0-beta.1

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 (363) hide show
  1. package/api/__tests__/migrate.test.js +19 -1
  2. package/api/migrate.d.ts +1 -1
  3. package/api/migrate.js +2 -1
  4. package/bin/cli.js +12 -27
  5. package/commands/__tests__/customObject.test.js +0 -2
  6. package/commands/__tests__/doctor.test.js +0 -2
  7. package/commands/__tests__/getStarted.test.js +0 -4
  8. package/commands/__tests__/project.test.js +0 -4
  9. package/commands/__tests__/upgrade.test.js +309 -0
  10. package/commands/account/__tests__/auth.test.js +180 -0
  11. package/commands/account/__tests__/list.test.js +128 -3
  12. package/commands/account/__tests__/rename.test.js +0 -2
  13. package/commands/account/__tests__/use.test.js +138 -0
  14. package/commands/account/auth.js +1 -1
  15. package/commands/account/clean.js +4 -3
  16. package/commands/account/createOverride.js +3 -2
  17. package/commands/account/info.js +2 -2
  18. package/commands/account/list.js +4 -4
  19. package/commands/account/remove.js +3 -2
  20. package/commands/account/removeOverride.js +3 -2
  21. package/commands/account/use.js +4 -3
  22. package/commands/app/__tests__/migrate.test.js +8 -25
  23. package/commands/app/migrate.js +10 -16
  24. package/commands/app/secret/__tests__/add.test.js +112 -0
  25. package/commands/app/secret/add.js +13 -13
  26. package/commands/auth.js +8 -2
  27. package/commands/cms/__tests__/fetch.test.js +114 -15
  28. package/commands/cms/__tests__/upload.test.js +308 -0
  29. package/commands/cms/__tests__/watch.test.js +212 -0
  30. package/commands/cms/app/create.js +2 -3
  31. package/commands/cms/convertFields.js +1 -1
  32. package/commands/cms/fetch.js +3 -2
  33. package/commands/cms/function/deploy.js +2 -2
  34. package/commands/cms/function/list.js +2 -3
  35. package/commands/cms/lighthouseScore.js +19 -27
  36. package/commands/cms/module/marketplace-validate.js +0 -1
  37. package/commands/cms/theme/__tests__/preview.test.js +2 -8
  38. package/commands/cms/theme/create.js +1 -1
  39. package/commands/cms/theme/marketplace-validate.js +0 -1
  40. package/commands/cms/theme/preview.d.ts +0 -1
  41. package/commands/cms/theme/preview.js +12 -52
  42. package/commands/cms/upload.js +3 -3
  43. package/commands/cms/watch.js +3 -3
  44. package/commands/customObject.js +0 -2
  45. package/commands/doctor.js +10 -2
  46. package/commands/filemanager/__tests__/upload.test.js +161 -0
  47. package/commands/getStarted.js +13 -3
  48. package/commands/hubdb/__tests__/list.test.js +0 -9
  49. package/commands/hubdb/list.js +6 -8
  50. package/commands/init.js +8 -2
  51. package/commands/mcp/__tests__/start.test.js +113 -3
  52. package/commands/mcp/setup.js +0 -7
  53. package/commands/mcp/start.d.ts +1 -1
  54. package/commands/mcp/start.js +0 -7
  55. package/commands/project/__tests__/add.test.js +0 -2
  56. package/commands/project/__tests__/create.test.js +2 -2
  57. package/commands/project/__tests__/deploy.test.js +0 -4
  58. package/commands/project/__tests__/dev.test.js +273 -0
  59. package/commands/project/__tests__/devUnifiedFlow.test.js +2 -5
  60. package/commands/project/__tests__/installDeps.test.js +0 -2
  61. package/commands/project/__tests__/lint.test.js +0 -5
  62. package/commands/project/__tests__/logs.test.js +24 -31
  63. package/commands/project/__tests__/migrate.test.js +7 -12
  64. package/commands/project/__tests__/updateDeps.test.js +0 -2
  65. package/commands/project/__tests__/upload.test.js +191 -0
  66. package/commands/project/__tests__/validate.test.js +314 -31
  67. package/commands/project/cloneApp.d.ts +1 -7
  68. package/commands/project/cloneApp.js +1 -149
  69. package/commands/project/create.js +3 -4
  70. package/commands/project/deploy.js +18 -7
  71. package/commands/project/dev/deprecatedFlow.js +0 -2
  72. package/commands/project/dev/index.js +23 -11
  73. package/commands/project/dev/unifiedFlow.d.ts +1 -1
  74. package/commands/project/dev/unifiedFlow.js +1 -4
  75. package/commands/project/list.js +4 -4
  76. package/commands/project/listBuilds.js +2 -7
  77. package/commands/project/logs.js +19 -12
  78. package/commands/project/migrate.js +3 -3
  79. package/commands/project/profile/add.js +1 -1
  80. package/commands/project/profile/delete.js +1 -1
  81. package/commands/project/upload.d.ts +1 -1
  82. package/commands/project/upload.js +13 -4
  83. package/commands/project/validate.js +85 -13
  84. package/commands/project/watch.js +7 -7
  85. package/commands/project.js +0 -4
  86. package/commands/sandbox/__tests__/create.test.js +0 -2
  87. package/commands/secret/__tests__/addSecret.test.js +140 -7
  88. package/commands/secret/addSecret.js +3 -1
  89. package/commands/testAccount/__tests__/create.test.js +6 -1
  90. package/commands/testAccount/__tests__/importData.test.js +0 -1
  91. package/commands/testAccount/create.d.ts +1 -0
  92. package/commands/testAccount/create.js +13 -5
  93. package/commands/upgrade.d.ts +8 -0
  94. package/commands/upgrade.js +119 -0
  95. package/lang/en.d.ts +88 -10
  96. package/lang/en.js +105 -26
  97. package/lib/__tests__/buildAccount.test.js +0 -13
  98. package/lib/__tests__/cliUpgradeUtils.test.js +131 -0
  99. package/lib/__tests__/commonOpts.test.js +0 -1
  100. package/lib/__tests__/dependencyManagement.test.js +633 -13
  101. package/lib/__tests__/developerTestAccounts.test.js +0 -1
  102. package/lib/__tests__/hasFeature.test.js +0 -6
  103. package/lib/__tests__/importData.test.js +0 -1
  104. package/lib/__tests__/npmCli.test.js +84 -0
  105. package/lib/__tests__/oauth.test.js +1 -11
  106. package/lib/__tests__/process.test.js +0 -1
  107. package/lib/__tests__/sandboxSync.test.js +0 -1
  108. package/lib/__tests__/sandboxes.test.js +0 -1
  109. package/lib/__tests__/serverlessLogs.test.js +0 -1
  110. package/lib/__tests__/usageTracking.test.js +39 -6
  111. package/lib/__tests__/validation.test.js +0 -1
  112. package/lib/app/__tests__/migrate.test.js +137 -12
  113. package/lib/app/migrate.d.ts +5 -2
  114. package/lib/app/migrate.js +30 -11
  115. package/lib/app/urls.d.ts +1 -1
  116. package/lib/buildAccount.d.ts +1 -1
  117. package/lib/cliUpgradeUtils.d.ts +22 -0
  118. package/lib/cliUpgradeUtils.js +62 -0
  119. package/lib/cmsAssets/api-sample.js +2 -5
  120. package/lib/cmsAssets/function.js +1 -9
  121. package/lib/cmsAssets/module.js +1 -9
  122. package/lib/cmsAssets/template.js +1 -9
  123. package/lib/configOptions.d.ts +0 -1
  124. package/lib/configOptions.js +1 -5
  125. package/lib/constants.d.ts +6 -0
  126. package/lib/constants.js +10 -4
  127. package/lib/dependencyManagement.d.ts +9 -0
  128. package/lib/dependencyManagement.js +127 -26
  129. package/lib/developerTestAccounts.d.ts +1 -1
  130. package/lib/doctor/Diagnosis.d.ts +1 -0
  131. package/lib/doctor/Diagnosis.js +7 -0
  132. package/lib/doctor/DiagnosticInfoBuilder.d.ts +2 -1
  133. package/lib/doctor/DiagnosticInfoBuilder.js +8 -4
  134. package/lib/doctor/Doctor.d.ts +12 -0
  135. package/lib/doctor/Doctor.js +283 -33
  136. package/lib/doctor/__tests__/Diagnosis.test.js +1 -0
  137. package/lib/doctor/__tests__/Doctor.test.js +201 -51
  138. package/lib/errorHandlers/__tests__/index.test.d.ts +1 -0
  139. package/lib/errorHandlers/__tests__/index.test.js +278 -0
  140. package/lib/errorHandlers/index.d.ts +1 -0
  141. package/lib/errorHandlers/index.js +14 -2
  142. package/lib/http.js +3 -1
  143. package/lib/links.js +2 -3
  144. package/lib/mcp/__tests__/setup.test.js +69 -2
  145. package/lib/mcp/setup.d.ts +1 -0
  146. package/lib/mcp/setup.js +37 -4
  147. package/lib/middleware/__tests__/configMiddleware.test.js +1 -43
  148. package/lib/middleware/__tests__/usageTrackingMiddleware.test.d.ts +1 -0
  149. package/lib/middleware/__tests__/usageTrackingMiddleware.test.js +44 -0
  150. package/lib/middleware/__tests__/yargsChecksMiddleware.test.js +0 -5
  151. package/lib/middleware/autoUpdateMiddleware.js +58 -57
  152. package/lib/middleware/configMiddleware.d.ts +0 -3
  153. package/lib/middleware/configMiddleware.js +0 -11
  154. package/lib/middleware/fireAlarmMiddleware.js +1 -1
  155. package/lib/middleware/spinniesMiddleware.d.ts +1 -0
  156. package/lib/middleware/spinniesMiddleware.js +4 -0
  157. package/lib/middleware/usageTrackingMiddleware.d.ts +13 -0
  158. package/lib/middleware/usageTrackingMiddleware.js +16 -0
  159. package/lib/{npm.d.ts → npm/npmCli.d.ts} +8 -3
  160. package/lib/npm/npmCli.js +59 -0
  161. package/lib/npm/packageJson.d.ts +24 -0
  162. package/lib/npm/packageJson.js +102 -0
  163. package/lib/npm/workspaces.d.ts +12 -0
  164. package/lib/npm/workspaces.js +48 -0
  165. package/lib/oauth.js +1 -3
  166. package/lib/projects/__tests__/AppDevModeInterface.test.js +40 -18
  167. package/lib/projects/__tests__/DevServerManager.test.js +1 -0
  168. package/lib/projects/__tests__/DevSessionManager.test.d.ts +1 -0
  169. package/lib/projects/__tests__/DevSessionManager.test.js +250 -0
  170. package/lib/projects/__tests__/LocalDevProcess.test.js +19 -6
  171. package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +0 -2
  172. package/lib/projects/__tests__/UIExtensionsDevModeInterface.test.js +0 -1
  173. package/lib/projects/__tests__/components.test.js +6 -22
  174. package/lib/projects/__tests__/deploy.test.js +0 -1
  175. package/lib/projects/__tests__/localDevProjectHelpers.test.js +3 -5
  176. package/lib/projects/__tests__/pollProjectBuildAndDeploy.test.d.ts +1 -0
  177. package/lib/projects/__tests__/pollProjectBuildAndDeploy.test.js +328 -0
  178. package/lib/projects/__tests__/projectProfiles.test.d.ts +1 -0
  179. package/lib/projects/__tests__/projectProfiles.test.js +441 -0
  180. package/lib/projects/__tests__/projects.test.js +0 -1
  181. package/lib/projects/__tests__/structure.test.js +0 -1
  182. package/lib/projects/__tests__/uieLinting.test.js +2 -11
  183. package/lib/projects/__tests__/upload.test.js +104 -3
  184. package/lib/projects/add/__tests__/legacyAddComponent.test.js +0 -2
  185. package/lib/projects/add/__tests__/v2AddComponent.test.js +2 -4
  186. package/lib/projects/add/v2AddComponent.js +2 -3
  187. package/lib/projects/components.d.ts +1 -1
  188. package/lib/projects/components.js +4 -4
  189. package/lib/projects/create/__tests__/legacy.test.js +0 -1
  190. package/lib/projects/create/__tests__/v2.test.js +0 -1
  191. package/lib/projects/create/v2.d.ts +1 -1
  192. package/lib/projects/create/v2.js +1 -1
  193. package/lib/projects/ensureProjectExists.js +0 -1
  194. package/lib/projects/localDev/AppDevModeInterface.js +9 -2
  195. package/lib/projects/localDev/DevSessionManager.d.ts +18 -0
  196. package/lib/projects/localDev/DevSessionManager.js +95 -0
  197. package/lib/projects/localDev/LocalDevLogger.d.ts +4 -0
  198. package/lib/projects/localDev/LocalDevLogger.js +18 -7
  199. package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +4 -3
  200. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +23 -12
  201. package/lib/projects/localDev/LocalDevProcess.d.ts +2 -1
  202. package/lib/projects/localDev/LocalDevProcess.js +18 -7
  203. package/lib/projects/localDev/LocalDevState.d.ts +3 -2
  204. package/lib/projects/localDev/helpers/account.d.ts +1 -1
  205. package/lib/projects/localDev/helpers/devSessionsApi.d.ts +9 -0
  206. package/lib/projects/localDev/helpers/devSessionsApi.js +19 -0
  207. package/lib/projects/localDev/helpers/project.d.ts +1 -1
  208. package/lib/projects/localDev/helpers/project.js +1 -2
  209. package/lib/projects/pollProjectBuildAndDeploy.js +4 -5
  210. package/lib/projects/projectProfiles.d.ts +17 -0
  211. package/lib/projects/projectProfiles.js +140 -0
  212. package/lib/projects/structure.d.ts +1 -1
  213. package/lib/projects/uieLinting.js +6 -8
  214. package/lib/projects/upload.d.ts +9 -1
  215. package/lib/projects/upload.js +11 -5
  216. package/lib/projects/urls.d.ts +1 -0
  217. package/lib/projects/urls.js +3 -3
  218. package/lib/prompts/__tests__/createDeveloperTestAccountConfigPrompt.test.js +8 -4
  219. package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +2 -0
  220. package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +19 -13
  221. package/lib/sandboxSync.d.ts +1 -1
  222. package/lib/sandboxes.d.ts +1 -1
  223. package/lib/serverlessLogs.js +0 -1
  224. package/lib/theme/__tests__/migrate.test.js +12 -4
  225. package/lib/theme/migrate.js +2 -3
  226. package/lib/ui/__tests__/SpinniesManager.test.js +0 -1
  227. package/lib/usageTracking.js +18 -0
  228. package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +2 -2
  229. package/mcp-server/tools/cms/HsCreateFunctionTool.js +2 -1
  230. package/mcp-server/tools/cms/HsCreateModuleTool.js +2 -1
  231. package/mcp-server/tools/cms/HsCreateTemplateTool.js +2 -1
  232. package/mcp-server/tools/cms/HsFunctionLogsTool.js +2 -2
  233. package/mcp-server/tools/cms/HsListFunctionsTool.js +2 -2
  234. package/mcp-server/tools/cms/HsListTool.js +2 -2
  235. package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +4 -4
  236. package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +4 -4
  237. package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +4 -4
  238. package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +4 -4
  239. package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +4 -4
  240. package/mcp-server/tools/cms/__tests__/HsListTool.test.js +4 -4
  241. package/mcp-server/tools/project/AddFeatureToProjectTool.js +4 -3
  242. package/mcp-server/tools/project/CreateProjectTool.js +4 -3
  243. package/mcp-server/tools/project/CreateTestAccountTool.d.ts +7 -2
  244. package/mcp-server/tools/project/CreateTestAccountTool.js +19 -9
  245. package/mcp-server/tools/project/DocFetchTool.js +2 -1
  246. package/mcp-server/tools/project/DocsSearchTool.js +2 -1
  247. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +4 -4
  248. package/mcp-server/tools/project/GetApplicationInfoTool.js +5 -5
  249. package/mcp-server/tools/project/GetConfigValuesTool.js +2 -1
  250. package/mcp-server/tools/project/UploadProjectTools.js +6 -3
  251. package/mcp-server/tools/project/ValidateProjectTool.js +2 -1
  252. package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +4 -2
  253. package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +4 -2
  254. package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +23 -4
  255. package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +3 -1
  256. package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +0 -1
  257. package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +3 -1
  258. package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +4 -2
  259. package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +8 -5
  260. package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.js +3 -1
  261. package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +3 -1
  262. package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +7 -3
  263. package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +3 -1
  264. package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +17 -3
  265. package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +3 -1
  266. package/mcp-server/utils/__tests__/content.test.js +0 -3
  267. package/mcp-server/utils/__tests__/feedbackTracking.test.js +0 -3
  268. package/mcp-server/utils/__tests__/project.test.js +65 -4
  269. package/mcp-server/utils/project.js +6 -2
  270. package/package.json +15 -17
  271. package/types/Cms.d.ts +1 -1
  272. package/types/Cms.js +2 -0
  273. package/types/LocalDev.d.ts +3 -2
  274. package/types/PackageJson.d.ts +10 -0
  275. package/types/PackageJson.js +1 -0
  276. package/types/ProjectComponents.d.ts +1 -1
  277. package/ui/components/BoxWithTitle.js +1 -1
  278. package/ui/components/Table.d.ts +89 -0
  279. package/ui/components/Table.js +246 -0
  280. package/ui/lib/table.d.ts +2 -0
  281. package/ui/lib/table.js +11 -0
  282. package/ui/playground/Playground.d.ts +5 -0
  283. package/ui/{views/UiSandbox.js → playground/Playground.js} +4 -4
  284. package/ui/{lib/ui-testing-utils.d.ts → playground/fixtures.d.ts} +1 -1
  285. package/ui/{lib/ui-testing-utils.js → playground/fixtures.js} +33 -1
  286. package/ui/render.d.ts +19 -0
  287. package/ui/render.js +44 -0
  288. package/commands/__tests__/create.test.js +0 -53
  289. package/commands/create.d.ts +0 -4
  290. package/commands/create.js +0 -137
  291. package/commands/customObject/__tests__/schema.test.js +0 -53
  292. package/commands/customObject/schema/create.d.ts +0 -4
  293. package/commands/customObject/schema/create.js +0 -34
  294. package/commands/customObject/schema/delete.d.ts +0 -4
  295. package/commands/customObject/schema/delete.js +0 -37
  296. package/commands/customObject/schema/fetch-all.d.ts +0 -4
  297. package/commands/customObject/schema/fetch-all.js +0 -32
  298. package/commands/customObject/schema/fetch.d.ts +0 -4
  299. package/commands/customObject/schema/fetch.js +0 -36
  300. package/commands/customObject/schema/list.d.ts +0 -4
  301. package/commands/customObject/schema/list.js +0 -26
  302. package/commands/customObject/schema/update.d.ts +0 -4
  303. package/commands/customObject/schema/update.js +0 -39
  304. package/commands/customObject/schema.d.ts +0 -3
  305. package/commands/customObject/schema.js +0 -31
  306. package/commands/fetch.d.ts +0 -4
  307. package/commands/fetch.js +0 -52
  308. package/commands/function/deploy.d.ts +0 -4
  309. package/commands/function/deploy.js +0 -31
  310. package/commands/function/list.d.ts +0 -4
  311. package/commands/function/list.js +0 -33
  312. package/commands/function/server.d.ts +0 -4
  313. package/commands/function/server.js +0 -57
  314. package/commands/function.d.ts +0 -3
  315. package/commands/function.js +0 -32
  316. package/commands/lint.d.ts +0 -4
  317. package/commands/lint.js +0 -31
  318. package/commands/list.d.ts +0 -4
  319. package/commands/list.js +0 -31
  320. package/commands/logs.d.ts +0 -4
  321. package/commands/logs.js +0 -58
  322. package/commands/module/marketplace-validate.d.ts +0 -4
  323. package/commands/module/marketplace-validate.js +0 -31
  324. package/commands/module.d.ts +0 -3
  325. package/commands/module.js +0 -23
  326. package/commands/mv.d.ts +0 -4
  327. package/commands/mv.js +0 -35
  328. package/commands/project/__tests__/migrateApp.test.js +0 -78
  329. package/commands/project/migrateApp.d.ts +0 -4
  330. package/commands/project/migrateApp.js +0 -55
  331. package/commands/remove.d.ts +0 -4
  332. package/commands/remove.js +0 -31
  333. package/commands/theme/generate-selectors.d.ts +0 -4
  334. package/commands/theme/generate-selectors.js +0 -30
  335. package/commands/theme/marketplace-validate.d.ts +0 -4
  336. package/commands/theme/marketplace-validate.js +0 -33
  337. package/commands/theme/preview.d.ts +0 -4
  338. package/commands/theme/preview.js +0 -59
  339. package/commands/theme.d.ts +0 -3
  340. package/commands/theme.js +0 -29
  341. package/commands/upload.d.ts +0 -4
  342. package/commands/upload.js +0 -62
  343. package/commands/watch.d.ts +0 -4
  344. package/commands/watch.js +0 -73
  345. package/lib/__tests__/npm.test.js +0 -57
  346. package/lib/__tests__/projectProfiles.test.js +0 -129
  347. package/lib/app/__tests__/migrate_legacy.test.js +0 -143
  348. package/lib/app/migrate_legacy.d.ts +0 -4
  349. package/lib/app/migrate_legacy.js +0 -121
  350. package/lib/npm.js +0 -33
  351. package/lib/projectProfiles.d.ts +0 -7
  352. package/lib/projectProfiles.js +0 -73
  353. package/lib/ui/table.d.ts +0 -3
  354. package/lib/ui/table.js +0 -63
  355. package/ui/index.d.ts +0 -1
  356. package/ui/index.js +0 -6
  357. package/ui/views/UiSandbox.d.ts +0 -5
  358. /package/commands/__tests__/{create.test.d.ts → upgrade.test.d.ts} +0 -0
  359. /package/commands/{customObject/__tests__/schema.test.d.ts → cms/__tests__/upload.test.d.ts} +0 -0
  360. /package/commands/{project/__tests__/migrateApp.test.d.ts → cms/__tests__/watch.test.d.ts} +0 -0
  361. /package/{lib/__tests__/npm.test.d.ts → commands/project/__tests__/dev.test.d.ts} +0 -0
  362. /package/lib/__tests__/{projectProfiles.test.d.ts → cliUpgradeUtils.test.d.ts} +0 -0
  363. /package/lib/{app/__tests__/migrate_legacy.test.d.ts → __tests__/npmCli.test.d.ts} +0 -0
@@ -1,32 +1,62 @@
1
1
  import { Doctor } from '../Doctor.js';
2
2
  import { hasMissingPackages as _hasMissingPackages } from '../../dependencyManagement.js';
3
3
  import { isPortManagerPortAvailable as _isPortManagerPortAvailable } from '@hubspot/local-dev-lib/portManager';
4
- import { accessTokenForPersonalAccessKey as _accessTokenForPersonalAccessKey, authorizedScopesForPortalAndUser as _authorizedScopesForPortalAndUser, scopesOnAccessToken as _scopesOnAccessToken, } from '@hubspot/local-dev-lib/personalAccessKey';
4
+ import { accessTokenForPersonalAccessKey as _accessTokenForPersonalAccessKey, scopesOnAccessToken as _scopesOnAccessToken, } from '@hubspot/local-dev-lib/personalAccessKey';
5
+ import { fetchScopeAuthorizationData as _fetchScopeAuthorizationData } from '@hubspot/local-dev-lib/api/localDevAuth';
5
6
  import { HubSpotHttpError } from '@hubspot/local-dev-lib/models/HubSpotHttpError';
6
- import { AxiosError } from 'axios';
7
+ import { AxiosError, AxiosHeaders } from 'axios';
7
8
  import { isSpecifiedError as _isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
8
9
  import { promisify as _promisify } from 'util';
9
10
  import { getConfigDefaultAccount as _getConfigDefaultAccount, getConfigDefaultAccountIfExists as _getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
10
- vi.mock('../../ui/logger.js');
11
+ import { validateProjectConfig as _validateProjectConfig } from '../../projects/config.js';
12
+ import { isV2Project as _isV2Project } from '../../projects/platformVersion.js';
13
+ import { validateSourceDirectory as _validateSourceDirectory, handleTranslate as _handleTranslate, } from '../../projects/upload.js';
14
+ import { validateProjectForProfile as _validateProjectForProfile } from '../../projects/projectProfiles.js';
15
+ import { getAllHsProfiles as _getAllHsProfiles } from '@hubspot/project-parsing-lib/profiles';
16
+ import { getLatestCliVersion as _getLatestCliVersion } from '../../cliUpgradeUtils.js';
11
17
  vi.mock('../Diagnosis');
12
18
  vi.mock('../../ui/SpinniesManager');
13
19
  vi.mock('../DiagnosticInfoBuilder');
14
20
  vi.mock('../../dependencyManagement');
15
- vi.mock('../../npm');
21
+ vi.mock('../../npm/npmCli');
16
22
  vi.mock('@hubspot/local-dev-lib/portManager');
17
23
  vi.mock('@hubspot/local-dev-lib/personalAccessKey');
24
+ vi.mock('@hubspot/local-dev-lib/api/localDevAuth');
18
25
  vi.mock('@hubspot/local-dev-lib/errors/index');
19
26
  vi.mock('@hubspot/local-dev-lib/config');
20
27
  vi.mock('util');
28
+ vi.mock('../../projects/config.js');
29
+ vi.mock('../../projects/platformVersion.js');
30
+ vi.mock('../../projects/upload.js');
31
+ vi.mock('../../projects/projectProfiles.js');
32
+ vi.mock('@hubspot/project-parsing-lib/profiles');
33
+ vi.mock('@hubspot/project-parsing-lib/constants');
34
+ vi.mock('../../cliUpgradeUtils.js');
21
35
  const hasMissingPackages = vi.mocked(_hasMissingPackages);
22
36
  const isPortManagerPortAvailable = vi.mocked(_isPortManagerPortAvailable);
23
37
  const utilPromisify = vi.mocked(_promisify);
24
38
  const accessTokenForPersonalAccessKey = vi.mocked(_accessTokenForPersonalAccessKey);
25
- const authorizedScopesForPortalAndUser = vi.mocked(_authorizedScopesForPortalAndUser);
39
+ const fetchScopeAuthorizationData = vi.mocked(_fetchScopeAuthorizationData);
26
40
  const scopesOnAccessToken = vi.mocked(_scopesOnAccessToken);
27
41
  const isSpecifiedError = vi.mocked(_isSpecifiedError);
28
42
  const getConfigDefaultAccount = vi.mocked(_getConfigDefaultAccount);
29
43
  const getConfigDefaultAccountIfExists = vi.mocked(_getConfigDefaultAccountIfExists);
44
+ const validateProjectConfig = vi.mocked(_validateProjectConfig);
45
+ const isV2Project = vi.mocked(_isV2Project);
46
+ const validateSourceDirectory = vi.mocked(_validateSourceDirectory);
47
+ const handleTranslate = vi.mocked(_handleTranslate);
48
+ const validateProjectForProfile = vi.mocked(_validateProjectForProfile);
49
+ const getAllHsProfiles = vi.mocked(_getAllHsProfiles);
50
+ const getLatestCliVersion = vi.mocked(_getLatestCliVersion);
51
+ function createMockScopeAuthorizationResponse(results) {
52
+ return {
53
+ data: { results },
54
+ status: 200,
55
+ statusText: 'OK',
56
+ headers: {},
57
+ config: { headers: new AxiosHeaders() },
58
+ };
59
+ }
30
60
  describe('lib/doctor/Doctor', () => {
31
61
  let doctor;
32
62
  // @ts-ignore
@@ -55,7 +85,7 @@ describe('lib/doctor/Doctor', () => {
55
85
  },
56
86
  },
57
87
  versions: {
58
- node: '18.1.2',
88
+ node: '20.1.2',
59
89
  '@hubspot/cli': '6.0.0',
60
90
  npm: '6.14.13',
61
91
  },
@@ -71,6 +101,11 @@ describe('lib/doctor/Doctor', () => {
71
101
  };
72
102
  getConfigDefaultAccount.mockReturnValue(mockAccount);
73
103
  getConfigDefaultAccountIfExists.mockReturnValue(mockAccount);
104
+ // Mock getLatestCliVersion to return valid versions by default
105
+ getLatestCliVersion.mockResolvedValue({
106
+ latest: '7.12.0',
107
+ next: '7.12.0-beta.1',
108
+ });
74
109
  doctor = new Doctor({
75
110
  generateDiagnosticInfo: vi.fn().mockResolvedValue({
76
111
  ...diagnosticInfo,
@@ -83,9 +118,6 @@ describe('lib/doctor/Doctor', () => {
83
118
  return JSON.stringify({ valid: true });
84
119
  }));
85
120
  });
86
- afterEach(() => {
87
- vi.clearAllMocks();
88
- });
89
121
  describe('CLI Checks', () => {
90
122
  describe('node version', () => {
91
123
  it('should add success section if node version is valid', async () => {
@@ -154,7 +186,7 @@ describe('lib/doctor/Doctor', () => {
154
186
  describe('Personal Access Key', () => {
155
187
  it('should add success sections if the access token is valid', async () => {
156
188
  scopesOnAccessToken.mockResolvedValueOnce(['scope1']);
157
- authorizedScopesForPortalAndUser.mockResolvedValueOnce([
189
+ fetchScopeAuthorizationData.mockResolvedValueOnce(createMockScopeAuthorizationResponse([
158
190
  {
159
191
  scopeGroup: {
160
192
  name: 'scope1',
@@ -164,7 +196,7 @@ describe('lib/doctor/Doctor', () => {
164
196
  portalAuthorized: true,
165
197
  userAuthorized: true,
166
198
  },
167
- ]);
199
+ ]));
168
200
  await doctor.diagnose();
169
201
  // @ts-expect-error Testing private method
170
202
  expect(doctor.diagnosis.addCLIConfigSection).toHaveBeenCalledWith({
@@ -247,47 +279,51 @@ describe('lib/doctor/Doctor', () => {
247
279
  message: 'Unable to determine if the portal is active',
248
280
  });
249
281
  });
250
- it('should warn when there are missing authorized scopes', async () => {
251
- scopesOnAccessToken.mockResolvedValueOnce(['scope1', 'scope2']);
252
- authorizedScopesForPortalAndUser.mockResolvedValueOnce([
253
- {
254
- scopeGroup: {
255
- name: 'scope1',
256
- shortDescription: 'scope1',
257
- longDescription: 'scope1',
258
- },
259
- portalAuthorized: true,
260
- userAuthorized: true,
261
- },
262
- {
263
- scopeGroup: {
264
- name: 'scope2',
265
- shortDescription: 'scope2',
266
- longDescription: 'scope2',
267
- },
268
- portalAuthorized: true,
269
- userAuthorized: true,
270
- },
271
- {
272
- scopeGroup: {
273
- name: 'scope3',
274
- shortDescription: 'scope3',
275
- longDescription: 'scope3',
276
- },
277
- portalAuthorized: true,
278
- userAuthorized: true,
279
- },
280
- ]);
281
- await doctor.diagnose();
282
- expect(doctor['diagnosis']?.addCLIConfigSection).toHaveBeenCalledWith({
283
- type: 'warning',
284
- message: 'Personal access key is valid, but there are more scopes available to your user that are not included in your key.',
285
- secondaryMessaging: expect.any(String),
286
- });
287
- });
282
+ // @TODO Restore test once PAK scope check functionality is restored
283
+ // it('should warn when there are missing authorized scopes', async () => {
284
+ // scopesOnAccessToken.mockResolvedValueOnce(['scope1', 'scope2']);
285
+ // fetchScopeAuthorizationData.mockResolvedValueOnce(
286
+ // createMockScopeAuthorizationResponse([
287
+ // {
288
+ // scopeGroup: {
289
+ // name: 'scope1',
290
+ // shortDescription: 'scope1',
291
+ // longDescription: 'scope1',
292
+ // },
293
+ // portalAuthorized: true,
294
+ // userAuthorized: true,
295
+ // },
296
+ // {
297
+ // scopeGroup: {
298
+ // name: 'scope2',
299
+ // shortDescription: 'scope2',
300
+ // longDescription: 'scope2',
301
+ // },
302
+ // portalAuthorized: true,
303
+ // userAuthorized: true,
304
+ // },
305
+ // {
306
+ // scopeGroup: {
307
+ // name: 'scope3',
308
+ // shortDescription: 'scope3',
309
+ // longDescription: 'scope3',
310
+ // },
311
+ // portalAuthorized: true,
312
+ // userAuthorized: true,
313
+ // },
314
+ // ])
315
+ // );
316
+ // await doctor.diagnose();
317
+ // expect(doctor['diagnosis']?.addCLIConfigSection).toHaveBeenCalledWith({
318
+ // type: 'warning',
319
+ // message:
320
+ // 'Personal access key is valid, but there are more scopes available to your user that are not included in your key.',
321
+ // secondaryMessaging: expect.any(String),
322
+ // });
323
+ // });
288
324
  it('should not warn when the missing scope is not authorized', async () => {
289
325
  scopesOnAccessToken.mockResolvedValueOnce(['scope1']);
290
- authorizedScopesForPortalAndUser.mockResolvedValueOnce([
326
+ fetchScopeAuthorizationData.mockResolvedValueOnce(createMockScopeAuthorizationResponse([
291
327
  {
292
328
  scopeGroup: {
293
329
  name: 'scope1',
@@ -306,7 +342,7 @@ describe('lib/doctor/Doctor', () => {
306
342
  portalAuthorized: true,
307
343
  userAuthorized: false,
308
344
  },
309
- ]);
345
+ ]));
310
346
  await doctor.diagnose();
311
347
  expect(doctor['diagnosis']?.addCLIConfigSection).toHaveBeenCalledWith({
312
348
  type: 'success',
@@ -407,4 +443,118 @@ describe('lib/doctor/Doctor', () => {
407
443
  });
408
444
  });
409
445
  });
446
+ describe('Networking Checks', () => {
447
+ it('should perform network connectivity check during diagnosis', async () => {
448
+ await doctor.diagnose();
449
+ // @ts-expect-error Testing private method
450
+ expect(doctor.diagnosis.addNetworkingSection).toHaveBeenCalled();
451
+ });
452
+ });
453
+ describe('Project Validation', () => {
454
+ it('should skip validation if no project config exists', async () => {
455
+ doctor = new Doctor({
456
+ generateDiagnosticInfo: vi.fn().mockResolvedValue({
457
+ ...diagnosticInfo,
458
+ project: { config: null },
459
+ }),
460
+ });
461
+ await doctor.diagnose();
462
+ // @ts-expect-error Testing private method
463
+ const projectSections = doctor.diagnosis.project?.sections || [];
464
+ const validationSections = projectSections.filter((s) => s.message?.includes('validation'));
465
+ expect(validationSections.length).toBe(0);
466
+ });
467
+ it('should validate V1 projects successfully', async () => {
468
+ validateProjectConfig.mockReturnValue(undefined);
469
+ isV2Project.mockReturnValue(false);
470
+ await doctor.diagnose();
471
+ // @ts-expect-error Testing private method
472
+ expect(doctor.diagnosis.addProjectSection).toHaveBeenCalledWith({
473
+ type: 'success',
474
+ message: 'Project configuration and structure is valid',
475
+ });
476
+ });
477
+ it('should handle invalid project config', async () => {
478
+ validateProjectConfig.mockImplementation(() => {
479
+ throw new Error('Invalid config');
480
+ });
481
+ await doctor.diagnose();
482
+ // @ts-expect-error Testing private method
483
+ expect(doctor.diagnosis.addProjectSection).toHaveBeenCalledWith({
484
+ type: 'error',
485
+ message: 'Project configuration is invalid',
486
+ secondaryMessaging: 'Invalid config',
487
+ });
488
+ });
489
+ it('should validate V2 projects with profiles', async () => {
490
+ validateProjectConfig.mockReturnValue(undefined);
491
+ isV2Project.mockReturnValue(true);
492
+ validateSourceDirectory.mockResolvedValue(undefined);
493
+ getAllHsProfiles.mockResolvedValue(['dev', 'prod']);
494
+ validateProjectForProfile.mockResolvedValue([]);
495
+ await doctor.diagnose();
496
+ expect(validateProjectForProfile).toHaveBeenCalledTimes(2);
497
+ // @ts-expect-error Testing private method
498
+ expect(doctor.diagnosis.addProjectSection).toHaveBeenCalledWith({
499
+ type: 'success',
500
+ message: 'Project configuration and structure is valid',
501
+ });
502
+ });
503
+ it('should report profile validation errors', async () => {
504
+ validateProjectConfig.mockReturnValue(undefined);
505
+ isV2Project.mockReturnValue(true);
506
+ validateSourceDirectory.mockResolvedValue(undefined);
507
+ getAllHsProfiles.mockResolvedValue(['dev']);
508
+ validateProjectForProfile.mockResolvedValue([
509
+ new Error('Validation error'),
510
+ ]);
511
+ await doctor.diagnose();
512
+ // @ts-expect-error Testing private method
513
+ expect(doctor.diagnosis.addProjectSection).toHaveBeenCalledWith({
514
+ type: 'error',
515
+ message: "Project validation failed with profile 'dev' applied",
516
+ secondaryMessaging: expect.any(String),
517
+ });
518
+ });
519
+ it('should validate V2 projects without profiles', async () => {
520
+ validateProjectConfig.mockReturnValue(undefined);
521
+ isV2Project.mockReturnValue(true);
522
+ validateSourceDirectory.mockResolvedValue(undefined);
523
+ getAllHsProfiles.mockResolvedValue([]);
524
+ handleTranslate.mockResolvedValue(undefined);
525
+ await doctor.diagnose();
526
+ expect(handleTranslate).toHaveBeenCalled();
527
+ // @ts-expect-error Testing private method
528
+ expect(doctor.diagnosis.addProjectSection).toHaveBeenCalledWith({
529
+ type: 'success',
530
+ message: 'Project configuration and structure is valid',
531
+ });
532
+ });
533
+ it('should handle translation failures', async () => {
534
+ validateProjectConfig.mockReturnValue(undefined);
535
+ isV2Project.mockReturnValue(true);
536
+ validateSourceDirectory.mockResolvedValue(undefined);
537
+ getAllHsProfiles.mockResolvedValue([]);
538
+ handleTranslate.mockRejectedValue(new Error('Translation failed'));
539
+ await doctor.diagnose();
540
+ // @ts-expect-error Testing private method
541
+ expect(doctor.diagnosis.addProjectSection).toHaveBeenCalledWith({
542
+ type: 'warning',
543
+ message: 'Project validation failed',
544
+ secondaryMessaging: expect.any(String),
545
+ });
546
+ });
547
+ it('should handle source directory validation errors', async () => {
548
+ validateProjectConfig.mockReturnValue(undefined);
549
+ isV2Project.mockReturnValue(true);
550
+ validateSourceDirectory.mockRejectedValue(new Error('Source directory invalid'));
551
+ await doctor.diagnose();
552
+ // @ts-expect-error Testing private method
553
+ expect(doctor.diagnosis.addProjectSection).toHaveBeenCalledWith({
554
+ type: 'error',
555
+ message: 'Project source directory validation failed',
556
+ secondaryMessaging: 'Source directory invalid',
557
+ });
558
+ });
559
+ });
410
560
  });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,278 @@
1
+ import { logError, debugError, ApiErrorContext, isErrorWithMessageOrReason, getErrorMessage, } from '../index.js';
2
+ import { uiLogger } from '../../ui/logger.js';
3
+ import { isHubSpotHttpError, isValidationError, } from '@hubspot/local-dev-lib/errors/index';
4
+ import { getConfig } from '@hubspot/local-dev-lib/config';
5
+ import { shouldSuppressError } from '../suppressError.js';
6
+ import { isProjectValidationError } from '../../errors/ProjectValidationError.js';
7
+ import { lib } from '../../../lang/en.js';
8
+ vi.mock('../../ui/logger.js');
9
+ vi.mock('@hubspot/local-dev-lib/errors/index');
10
+ vi.mock('@hubspot/local-dev-lib/config');
11
+ vi.mock('../suppressError.js');
12
+ vi.mock('../../errors/ProjectValidationError.js');
13
+ describe('lib/errorHandlers/index', () => {
14
+ const uiLoggerErrorMock = uiLogger.error;
15
+ const uiLoggerDebugMock = uiLogger.debug;
16
+ const isHubSpotHttpErrorMock = isHubSpotHttpError;
17
+ const isValidationErrorMock = isValidationError;
18
+ const getConfigMock = getConfig;
19
+ const shouldSuppressErrorMock = shouldSuppressError;
20
+ const isProjectValidationErrorMock = isProjectValidationError;
21
+ beforeEach(() => {
22
+ vi.clearAllMocks();
23
+ isHubSpotHttpErrorMock.mockReturnValue(false);
24
+ isValidationErrorMock.mockReturnValue(false);
25
+ shouldSuppressErrorMock.mockReturnValue(false);
26
+ isProjectValidationErrorMock.mockReturnValue(false);
27
+ getConfigMock.mockReturnValue({});
28
+ });
29
+ describe('logError', () => {
30
+ it('logs ProjectValidationError message and returns early', () => {
31
+ const error = {
32
+ message: 'Project validation failed',
33
+ name: 'ProjectValidationError',
34
+ };
35
+ isProjectValidationErrorMock.mockReturnValue(true);
36
+ logError(error);
37
+ expect(uiLoggerErrorMock).toHaveBeenCalledWith('Project validation failed');
38
+ expect(uiLoggerErrorMock).toHaveBeenCalledTimes(1);
39
+ });
40
+ it('returns early when error should be suppressed', () => {
41
+ const error = new Error('Suppressed error');
42
+ shouldSuppressErrorMock.mockReturnValue(true);
43
+ logError(error);
44
+ expect(shouldSuppressErrorMock).toHaveBeenCalled();
45
+ expect(uiLoggerErrorMock).not.toHaveBeenCalled();
46
+ });
47
+ it('logs validation errors for HubSpotHttpError with validation errors', () => {
48
+ const mockError = {
49
+ formattedValidationErrors: vi
50
+ .fn()
51
+ .mockReturnValue('Formatted validation errors'),
52
+ updateContext: vi.fn(),
53
+ context: {},
54
+ };
55
+ isHubSpotHttpErrorMock.mockReturnValue(true);
56
+ isValidationErrorMock.mockReturnValue(true);
57
+ logError(mockError);
58
+ expect(mockError.formattedValidationErrors).toHaveBeenCalled();
59
+ expect(uiLoggerErrorMock).toHaveBeenCalledWith('Formatted validation errors');
60
+ });
61
+ it('logs error message for errors with message property', () => {
62
+ const error = new Error('Something went wrong');
63
+ logError(error);
64
+ expect(uiLoggerErrorMock).toHaveBeenCalledWith('Something went wrong');
65
+ });
66
+ it('logs error with both message and reason', () => {
67
+ const error = { message: 'Error message', reason: 'Error reason' };
68
+ logError(error);
69
+ expect(uiLoggerErrorMock).toHaveBeenCalledWith('Error message Error reason');
70
+ });
71
+ it('logs unknown error message for errors without message or reason', () => {
72
+ const error = { foo: 'bar' };
73
+ logError(error);
74
+ expect(uiLoggerErrorMock).toHaveBeenCalledWith(lib.errorHandlers.index.unknownErrorOccurred);
75
+ });
76
+ it('calls updateContext on HubSpotHttpError', () => {
77
+ const mockError = {
78
+ updateContext: vi.fn(),
79
+ context: {},
80
+ message: 'test',
81
+ };
82
+ isHubSpotHttpErrorMock.mockReturnValue(true);
83
+ logError(mockError);
84
+ expect(mockError.updateContext).toHaveBeenCalled();
85
+ });
86
+ describe('timeout error handling', () => {
87
+ it('shows config timeout message for direct ETIMEDOUT error matching default timeout', () => {
88
+ const mockError = {
89
+ code: 'ETIMEDOUT',
90
+ timeout: 15000,
91
+ updateContext: vi.fn(),
92
+ context: {},
93
+ message: 'Timeout',
94
+ };
95
+ isHubSpotHttpErrorMock.mockReturnValue(true);
96
+ getConfigMock.mockReturnValue({ httpTimeout: 15000 });
97
+ logError(mockError);
98
+ expect(uiLoggerErrorMock).toHaveBeenCalledTimes(2);
99
+ expect(uiLoggerErrorMock).toHaveBeenNthCalledWith(1, 'Timeout');
100
+ expect(uiLoggerErrorMock).toHaveBeenNthCalledWith(2, lib.errorHandlers.index.configTimeoutErrorOccurred(15000, 'hs config set'));
101
+ });
102
+ it('shows generic timeout message for direct ETIMEDOUT error with custom timeout', () => {
103
+ const mockError = {
104
+ code: 'ETIMEDOUT',
105
+ timeout: 30000,
106
+ updateContext: vi.fn(),
107
+ context: {},
108
+ message: 'Timeout',
109
+ };
110
+ isHubSpotHttpErrorMock.mockReturnValue(true);
111
+ getConfigMock.mockReturnValue({ httpTimeout: 15000 });
112
+ logError(mockError);
113
+ expect(uiLoggerErrorMock).toHaveBeenCalledTimes(2);
114
+ expect(uiLoggerErrorMock).toHaveBeenNthCalledWith(2, lib.errorHandlers.index.genericTimeoutErrorOccurred);
115
+ });
116
+ it('detects timeout error wrapped in error.cause', () => {
117
+ const causeError = {
118
+ code: 'ETIMEDOUT',
119
+ timeout: 15000,
120
+ name: 'HubSpotHttpError',
121
+ };
122
+ const wrapperError = new Error('Assets unavailable');
123
+ Object.defineProperty(wrapperError, 'cause', {
124
+ value: causeError,
125
+ writable: true,
126
+ });
127
+ isHubSpotHttpErrorMock.mockImplementation(err => {
128
+ return err === causeError;
129
+ });
130
+ getConfigMock.mockReturnValue({ httpTimeout: 15000 });
131
+ logError(wrapperError);
132
+ expect(uiLoggerErrorMock).toHaveBeenCalledWith('Assets unavailable');
133
+ expect(uiLoggerErrorMock).toHaveBeenCalledWith(lib.errorHandlers.index.configTimeoutErrorOccurred(15000, 'hs config set'));
134
+ });
135
+ it('shows generic timeout message for wrapped timeout with different timeout value', () => {
136
+ const causeError = {
137
+ code: 'ETIMEDOUT',
138
+ timeout: 60000,
139
+ name: 'HubSpotHttpError',
140
+ };
141
+ const wrapperError = new Error('Assets unavailable');
142
+ Object.defineProperty(wrapperError, 'cause', {
143
+ value: causeError,
144
+ writable: true,
145
+ });
146
+ isHubSpotHttpErrorMock.mockImplementation(err => {
147
+ return err === causeError;
148
+ });
149
+ getConfigMock.mockReturnValue({ httpTimeout: 15000 });
150
+ logError(wrapperError);
151
+ expect(uiLoggerErrorMock).toHaveBeenCalledTimes(2);
152
+ expect(uiLoggerErrorMock).toHaveBeenNthCalledWith(2, lib.errorHandlers.index.genericTimeoutErrorOccurred);
153
+ });
154
+ it('does not show timeout message for non-timeout errors', () => {
155
+ const error = new Error('Regular error');
156
+ logError(error);
157
+ expect(uiLoggerErrorMock).toHaveBeenCalledTimes(1);
158
+ expect(uiLoggerErrorMock).toHaveBeenCalledWith('Regular error');
159
+ });
160
+ });
161
+ });
162
+ describe('debugError', () => {
163
+ it('logs HubSpotHttpError using toString', () => {
164
+ const mockError = {
165
+ toString: vi.fn().mockReturnValue('HubSpotHttpError details'),
166
+ };
167
+ isHubSpotHttpErrorMock.mockReturnValue(true);
168
+ debugError(mockError);
169
+ expect(uiLoggerDebugMock).toHaveBeenCalledWith('HubSpotHttpError details');
170
+ });
171
+ it('logs regular error using lib.errorHandlers.index.errorOccurred', () => {
172
+ const error = new Error('Regular error');
173
+ debugError(error);
174
+ expect(uiLoggerDebugMock).toHaveBeenCalledWith(lib.errorHandlers.index.errorOccurred('Error: Regular error'));
175
+ });
176
+ it('logs error.cause when it is a HubSpotHttpError', () => {
177
+ const causeError = {
178
+ toString: vi.fn().mockReturnValue('Cause error details'),
179
+ };
180
+ const error = new Error('Wrapper error');
181
+ Object.defineProperty(error, 'cause', {
182
+ value: causeError,
183
+ writable: true,
184
+ });
185
+ isHubSpotHttpErrorMock.mockImplementation(err => {
186
+ return err === causeError;
187
+ });
188
+ debugError(error);
189
+ expect(causeError.toString).toHaveBeenCalled();
190
+ expect(uiLoggerDebugMock).toHaveBeenCalledWith('Cause error details');
191
+ });
192
+ it('logs error.cause using lib.errorHandlers.index.errorCause when not a HubSpotHttpError', () => {
193
+ const causeError = { customField: 'value' };
194
+ const error = new Error('Wrapper error');
195
+ Object.defineProperty(error, 'cause', {
196
+ value: causeError,
197
+ writable: true,
198
+ });
199
+ debugError(error);
200
+ expect(uiLoggerDebugMock).toHaveBeenCalledWith(expect.stringMatching(/^Cause:/));
201
+ });
202
+ it('logs context using lib.errorHandlers.index.errorContext when provided', () => {
203
+ const error = new Error('Error');
204
+ const context = new ApiErrorContext({
205
+ accountId: 123,
206
+ request: '/api/test',
207
+ });
208
+ debugError(error, context);
209
+ expect(uiLoggerDebugMock).toHaveBeenCalledWith(expect.stringMatching(/^Context:/));
210
+ });
211
+ });
212
+ describe('ApiErrorContext', () => {
213
+ it('creates context with all properties', () => {
214
+ const context = new ApiErrorContext({
215
+ accountId: 123,
216
+ request: '/api/test',
217
+ payload: '{"data": "value"}',
218
+ projectName: 'my-project',
219
+ });
220
+ expect(context.accountId).toBe(123);
221
+ expect(context.request).toBe('/api/test');
222
+ expect(context.payload).toBe('{"data": "value"}');
223
+ expect(context.projectName).toBe('my-project');
224
+ });
225
+ it('creates context with default values', () => {
226
+ const context = new ApiErrorContext();
227
+ expect(context.accountId).toBeUndefined();
228
+ expect(context.request).toBe('');
229
+ expect(context.payload).toBe('');
230
+ expect(context.projectName).toBe('');
231
+ });
232
+ it('creates context with partial properties', () => {
233
+ const context = new ApiErrorContext({
234
+ accountId: 456,
235
+ });
236
+ expect(context.accountId).toBe(456);
237
+ expect(context.request).toBe('');
238
+ expect(context.payload).toBe('');
239
+ expect(context.projectName).toBe('');
240
+ });
241
+ });
242
+ describe('isErrorWithMessageOrReason', () => {
243
+ it('returns true for object with message property', () => {
244
+ expect(isErrorWithMessageOrReason({ message: 'test' })).toBe(true);
245
+ });
246
+ it('returns true for object with reason property', () => {
247
+ expect(isErrorWithMessageOrReason({ reason: 'test' })).toBe(true);
248
+ });
249
+ it('returns true for object with both message and reason', () => {
250
+ expect(isErrorWithMessageOrReason({ message: 'msg', reason: 'rsn' })).toBe(true);
251
+ });
252
+ it('returns true for Error instances', () => {
253
+ expect(isErrorWithMessageOrReason(new Error('test'))).toBe(true);
254
+ });
255
+ it('returns false for null', () => {
256
+ expect(isErrorWithMessageOrReason(null)).toBe(false);
257
+ });
258
+ it('returns false for undefined', () => {
259
+ expect(isErrorWithMessageOrReason(undefined)).toBe(false);
260
+ });
261
+ it('returns false for primitive values', () => {
262
+ expect(isErrorWithMessageOrReason('string')).toBe(false);
263
+ expect(isErrorWithMessageOrReason(123)).toBe(false);
264
+ expect(isErrorWithMessageOrReason(true)).toBe(false);
265
+ });
266
+ it('returns false for object without message or reason', () => {
267
+ expect(isErrorWithMessageOrReason({ foo: 'bar' })).toBe(false);
268
+ });
269
+ it('returns false for empty object', () => {
270
+ expect(isErrorWithMessageOrReason({})).toBe(false);
271
+ });
272
+ });
273
+ describe('getErrorMessage', () => {
274
+ it('returns message from Error instance', () => {
275
+ expect(getErrorMessage(new Error('Error message'))).toBe('Error message');
276
+ });
277
+ });
278
+ });
@@ -16,3 +16,4 @@ export declare function isErrorWithMessageOrReason(error: unknown): error is {
16
16
  message?: string;
17
17
  reason?: string;
18
18
  };
19
+ export declare function getErrorMessage(error: unknown): string;
@@ -36,12 +36,21 @@ export function logError(error, context) {
36
36
  // Unknown errors
37
37
  uiLogger.error(lib.errorHandlers.index.unknownErrorOccurred);
38
38
  }
39
+ let timeoutError = null;
39
40
  if (isHubSpotHttpError(error) && error.code === 'ETIMEDOUT') {
41
+ timeoutError = error;
42
+ }
43
+ else if (error instanceof Error &&
44
+ isHubSpotHttpError(error.cause) &&
45
+ error.cause.code === 'ETIMEDOUT') {
46
+ timeoutError = error.cause;
47
+ }
48
+ if (timeoutError) {
40
49
  const config = getConfig();
41
50
  const defaultTimeout = config?.httpTimeout;
42
51
  // Timeout was caused by the default timeout
43
- if (error.timeout && defaultTimeout === error.timeout) {
44
- uiLogger.error(lib.errorHandlers.index.configTimeoutErrorOccurred(error.timeout, 'hs config set'));
52
+ if (timeoutError.timeout && defaultTimeout === timeoutError.timeout) {
53
+ uiLogger.error(lib.errorHandlers.index.configTimeoutErrorOccurred(timeoutError.timeout, 'hs config set'));
45
54
  }
46
55
  // Timeout was caused by a custom timeout set by the CLI or LDL
47
56
  else {
@@ -85,3 +94,6 @@ export function isErrorWithMessageOrReason(error) {
85
94
  error !== null &&
86
95
  ('message' in error || 'reason' in error));
87
96
  }
97
+ export function getErrorMessage(error) {
98
+ return error instanceof Error ? error.message : `${error}`;
99
+ }