@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.
- package/api/__tests__/migrate.test.js +19 -1
- package/api/migrate.d.ts +1 -1
- package/api/migrate.js +2 -1
- package/bin/cli.js +12 -27
- package/commands/__tests__/customObject.test.js +0 -2
- package/commands/__tests__/doctor.test.js +0 -2
- package/commands/__tests__/getStarted.test.js +0 -4
- package/commands/__tests__/project.test.js +0 -4
- package/commands/__tests__/upgrade.test.js +309 -0
- package/commands/account/__tests__/auth.test.js +180 -0
- package/commands/account/__tests__/list.test.js +128 -3
- package/commands/account/__tests__/rename.test.js +0 -2
- package/commands/account/__tests__/use.test.js +138 -0
- package/commands/account/auth.js +1 -1
- package/commands/account/clean.js +4 -3
- package/commands/account/createOverride.js +3 -2
- package/commands/account/info.js +2 -2
- package/commands/account/list.js +4 -4
- package/commands/account/remove.js +3 -2
- package/commands/account/removeOverride.js +3 -2
- package/commands/account/use.js +4 -3
- package/commands/app/__tests__/migrate.test.js +8 -25
- package/commands/app/migrate.js +10 -16
- package/commands/app/secret/__tests__/add.test.js +112 -0
- package/commands/app/secret/add.js +13 -13
- package/commands/auth.js +8 -2
- package/commands/cms/__tests__/fetch.test.js +114 -15
- package/commands/cms/__tests__/upload.test.js +308 -0
- package/commands/cms/__tests__/watch.test.js +212 -0
- package/commands/cms/app/create.js +2 -3
- package/commands/cms/convertFields.js +1 -1
- package/commands/cms/fetch.js +3 -2
- package/commands/cms/function/deploy.js +2 -2
- package/commands/cms/function/list.js +2 -3
- package/commands/cms/lighthouseScore.js +19 -27
- package/commands/cms/module/marketplace-validate.js +0 -1
- package/commands/cms/theme/__tests__/preview.test.js +2 -8
- package/commands/cms/theme/create.js +1 -1
- package/commands/cms/theme/marketplace-validate.js +0 -1
- package/commands/cms/theme/preview.d.ts +0 -1
- package/commands/cms/theme/preview.js +12 -52
- package/commands/cms/upload.js +3 -3
- package/commands/cms/watch.js +3 -3
- package/commands/customObject.js +0 -2
- package/commands/doctor.js +10 -2
- package/commands/filemanager/__tests__/upload.test.js +161 -0
- package/commands/getStarted.js +13 -3
- package/commands/hubdb/__tests__/list.test.js +0 -9
- package/commands/hubdb/list.js +6 -8
- package/commands/init.js +8 -2
- package/commands/mcp/__tests__/start.test.js +113 -3
- package/commands/mcp/setup.js +0 -7
- package/commands/mcp/start.d.ts +1 -1
- package/commands/mcp/start.js +0 -7
- package/commands/project/__tests__/add.test.js +0 -2
- package/commands/project/__tests__/create.test.js +2 -2
- package/commands/project/__tests__/deploy.test.js +0 -4
- package/commands/project/__tests__/dev.test.js +273 -0
- package/commands/project/__tests__/devUnifiedFlow.test.js +2 -5
- package/commands/project/__tests__/installDeps.test.js +0 -2
- package/commands/project/__tests__/lint.test.js +0 -5
- package/commands/project/__tests__/logs.test.js +24 -31
- package/commands/project/__tests__/migrate.test.js +7 -12
- package/commands/project/__tests__/updateDeps.test.js +0 -2
- package/commands/project/__tests__/upload.test.js +191 -0
- package/commands/project/__tests__/validate.test.js +314 -31
- package/commands/project/cloneApp.d.ts +1 -7
- package/commands/project/cloneApp.js +1 -149
- package/commands/project/create.js +3 -4
- package/commands/project/deploy.js +18 -7
- package/commands/project/dev/deprecatedFlow.js +0 -2
- package/commands/project/dev/index.js +23 -11
- package/commands/project/dev/unifiedFlow.d.ts +1 -1
- package/commands/project/dev/unifiedFlow.js +1 -4
- package/commands/project/list.js +4 -4
- package/commands/project/listBuilds.js +2 -7
- package/commands/project/logs.js +19 -12
- package/commands/project/migrate.js +3 -3
- package/commands/project/profile/add.js +1 -1
- package/commands/project/profile/delete.js +1 -1
- package/commands/project/upload.d.ts +1 -1
- package/commands/project/upload.js +13 -4
- package/commands/project/validate.js +85 -13
- package/commands/project/watch.js +7 -7
- package/commands/project.js +0 -4
- package/commands/sandbox/__tests__/create.test.js +0 -2
- package/commands/secret/__tests__/addSecret.test.js +140 -7
- package/commands/secret/addSecret.js +3 -1
- package/commands/testAccount/__tests__/create.test.js +6 -1
- package/commands/testAccount/__tests__/importData.test.js +0 -1
- package/commands/testAccount/create.d.ts +1 -0
- package/commands/testAccount/create.js +13 -5
- package/commands/upgrade.d.ts +8 -0
- package/commands/upgrade.js +119 -0
- package/lang/en.d.ts +88 -10
- package/lang/en.js +105 -26
- package/lib/__tests__/buildAccount.test.js +0 -13
- package/lib/__tests__/cliUpgradeUtils.test.js +131 -0
- package/lib/__tests__/commonOpts.test.js +0 -1
- package/lib/__tests__/dependencyManagement.test.js +633 -13
- package/lib/__tests__/developerTestAccounts.test.js +0 -1
- package/lib/__tests__/hasFeature.test.js +0 -6
- package/lib/__tests__/importData.test.js +0 -1
- package/lib/__tests__/npmCli.test.js +84 -0
- package/lib/__tests__/oauth.test.js +1 -11
- package/lib/__tests__/process.test.js +0 -1
- package/lib/__tests__/sandboxSync.test.js +0 -1
- package/lib/__tests__/sandboxes.test.js +0 -1
- package/lib/__tests__/serverlessLogs.test.js +0 -1
- package/lib/__tests__/usageTracking.test.js +39 -6
- package/lib/__tests__/validation.test.js +0 -1
- package/lib/app/__tests__/migrate.test.js +137 -12
- package/lib/app/migrate.d.ts +5 -2
- package/lib/app/migrate.js +30 -11
- package/lib/app/urls.d.ts +1 -1
- package/lib/buildAccount.d.ts +1 -1
- package/lib/cliUpgradeUtils.d.ts +22 -0
- package/lib/cliUpgradeUtils.js +62 -0
- package/lib/cmsAssets/api-sample.js +2 -5
- package/lib/cmsAssets/function.js +1 -9
- package/lib/cmsAssets/module.js +1 -9
- package/lib/cmsAssets/template.js +1 -9
- package/lib/configOptions.d.ts +0 -1
- package/lib/configOptions.js +1 -5
- package/lib/constants.d.ts +6 -0
- package/lib/constants.js +10 -4
- package/lib/dependencyManagement.d.ts +9 -0
- package/lib/dependencyManagement.js +127 -26
- package/lib/developerTestAccounts.d.ts +1 -1
- package/lib/doctor/Diagnosis.d.ts +1 -0
- package/lib/doctor/Diagnosis.js +7 -0
- package/lib/doctor/DiagnosticInfoBuilder.d.ts +2 -1
- package/lib/doctor/DiagnosticInfoBuilder.js +8 -4
- package/lib/doctor/Doctor.d.ts +12 -0
- package/lib/doctor/Doctor.js +283 -33
- package/lib/doctor/__tests__/Diagnosis.test.js +1 -0
- package/lib/doctor/__tests__/Doctor.test.js +201 -51
- package/lib/errorHandlers/__tests__/index.test.d.ts +1 -0
- package/lib/errorHandlers/__tests__/index.test.js +278 -0
- package/lib/errorHandlers/index.d.ts +1 -0
- package/lib/errorHandlers/index.js +14 -2
- package/lib/http.js +3 -1
- package/lib/links.js +2 -3
- package/lib/mcp/__tests__/setup.test.js +69 -2
- package/lib/mcp/setup.d.ts +1 -0
- package/lib/mcp/setup.js +37 -4
- package/lib/middleware/__tests__/configMiddleware.test.js +1 -43
- package/lib/middleware/__tests__/usageTrackingMiddleware.test.d.ts +1 -0
- package/lib/middleware/__tests__/usageTrackingMiddleware.test.js +44 -0
- package/lib/middleware/__tests__/yargsChecksMiddleware.test.js +0 -5
- package/lib/middleware/autoUpdateMiddleware.js +58 -57
- package/lib/middleware/configMiddleware.d.ts +0 -3
- package/lib/middleware/configMiddleware.js +0 -11
- package/lib/middleware/fireAlarmMiddleware.js +1 -1
- package/lib/middleware/spinniesMiddleware.d.ts +1 -0
- package/lib/middleware/spinniesMiddleware.js +4 -0
- package/lib/middleware/usageTrackingMiddleware.d.ts +13 -0
- package/lib/middleware/usageTrackingMiddleware.js +16 -0
- package/lib/{npm.d.ts → npm/npmCli.d.ts} +8 -3
- package/lib/npm/npmCli.js +59 -0
- package/lib/npm/packageJson.d.ts +24 -0
- package/lib/npm/packageJson.js +102 -0
- package/lib/npm/workspaces.d.ts +12 -0
- package/lib/npm/workspaces.js +48 -0
- package/lib/oauth.js +1 -3
- package/lib/projects/__tests__/AppDevModeInterface.test.js +40 -18
- package/lib/projects/__tests__/DevServerManager.test.js +1 -0
- package/lib/projects/__tests__/DevSessionManager.test.d.ts +1 -0
- package/lib/projects/__tests__/DevSessionManager.test.js +250 -0
- package/lib/projects/__tests__/LocalDevProcess.test.js +19 -6
- package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +0 -2
- package/lib/projects/__tests__/UIExtensionsDevModeInterface.test.js +0 -1
- package/lib/projects/__tests__/components.test.js +6 -22
- package/lib/projects/__tests__/deploy.test.js +0 -1
- package/lib/projects/__tests__/localDevProjectHelpers.test.js +3 -5
- package/lib/projects/__tests__/pollProjectBuildAndDeploy.test.d.ts +1 -0
- package/lib/projects/__tests__/pollProjectBuildAndDeploy.test.js +328 -0
- package/lib/projects/__tests__/projectProfiles.test.d.ts +1 -0
- package/lib/projects/__tests__/projectProfiles.test.js +441 -0
- package/lib/projects/__tests__/projects.test.js +0 -1
- package/lib/projects/__tests__/structure.test.js +0 -1
- package/lib/projects/__tests__/uieLinting.test.js +2 -11
- package/lib/projects/__tests__/upload.test.js +104 -3
- package/lib/projects/add/__tests__/legacyAddComponent.test.js +0 -2
- package/lib/projects/add/__tests__/v2AddComponent.test.js +2 -4
- package/lib/projects/add/v2AddComponent.js +2 -3
- package/lib/projects/components.d.ts +1 -1
- package/lib/projects/components.js +4 -4
- package/lib/projects/create/__tests__/legacy.test.js +0 -1
- package/lib/projects/create/__tests__/v2.test.js +0 -1
- package/lib/projects/create/v2.d.ts +1 -1
- package/lib/projects/create/v2.js +1 -1
- package/lib/projects/ensureProjectExists.js +0 -1
- package/lib/projects/localDev/AppDevModeInterface.js +9 -2
- package/lib/projects/localDev/DevSessionManager.d.ts +18 -0
- package/lib/projects/localDev/DevSessionManager.js +95 -0
- package/lib/projects/localDev/LocalDevLogger.d.ts +4 -0
- package/lib/projects/localDev/LocalDevLogger.js +18 -7
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +4 -3
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +23 -12
- package/lib/projects/localDev/LocalDevProcess.d.ts +2 -1
- package/lib/projects/localDev/LocalDevProcess.js +18 -7
- package/lib/projects/localDev/LocalDevState.d.ts +3 -2
- package/lib/projects/localDev/helpers/account.d.ts +1 -1
- package/lib/projects/localDev/helpers/devSessionsApi.d.ts +9 -0
- package/lib/projects/localDev/helpers/devSessionsApi.js +19 -0
- package/lib/projects/localDev/helpers/project.d.ts +1 -1
- package/lib/projects/localDev/helpers/project.js +1 -2
- package/lib/projects/pollProjectBuildAndDeploy.js +4 -5
- package/lib/projects/projectProfiles.d.ts +17 -0
- package/lib/projects/projectProfiles.js +140 -0
- package/lib/projects/structure.d.ts +1 -1
- package/lib/projects/uieLinting.js +6 -8
- package/lib/projects/upload.d.ts +9 -1
- package/lib/projects/upload.js +11 -5
- package/lib/projects/urls.d.ts +1 -0
- package/lib/projects/urls.js +3 -3
- package/lib/prompts/__tests__/createDeveloperTestAccountConfigPrompt.test.js +8 -4
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.d.ts +2 -0
- package/lib/prompts/createDeveloperTestAccountConfigPrompt.js +19 -13
- package/lib/sandboxSync.d.ts +1 -1
- package/lib/sandboxes.d.ts +1 -1
- package/lib/serverlessLogs.js +0 -1
- package/lib/theme/__tests__/migrate.test.js +12 -4
- package/lib/theme/migrate.js +2 -3
- package/lib/ui/__tests__/SpinniesManager.test.js +0 -1
- package/lib/usageTracking.js +18 -0
- package/mcp-server/tools/cms/HsCreateFunctionTool.d.ts +2 -2
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +2 -1
- package/mcp-server/tools/cms/HsCreateModuleTool.js +2 -1
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +2 -1
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +2 -2
- package/mcp-server/tools/cms/HsListFunctionsTool.js +2 -2
- package/mcp-server/tools/cms/HsListTool.js +2 -2
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +4 -4
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +4 -4
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +4 -4
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +4 -4
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +4 -4
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +4 -4
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +4 -3
- package/mcp-server/tools/project/CreateProjectTool.js +4 -3
- package/mcp-server/tools/project/CreateTestAccountTool.d.ts +7 -2
- package/mcp-server/tools/project/CreateTestAccountTool.js +19 -9
- package/mcp-server/tools/project/DocFetchTool.js +2 -1
- package/mcp-server/tools/project/DocsSearchTool.js +2 -1
- package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +4 -4
- package/mcp-server/tools/project/GetApplicationInfoTool.js +5 -5
- package/mcp-server/tools/project/GetConfigValuesTool.js +2 -1
- package/mcp-server/tools/project/UploadProjectTools.js +6 -3
- package/mcp-server/tools/project/ValidateProjectTool.js +2 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +4 -2
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +4 -2
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +23 -4
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +3 -1
- package/mcp-server/tools/project/__tests__/DocFetchTool.test.js +0 -1
- package/mcp-server/tools/project/__tests__/DocsSearchTool.test.js +3 -1
- package/mcp-server/tools/project/__tests__/GetApiUsagePatternsByAppIdTool.test.js +4 -2
- package/mcp-server/tools/project/__tests__/GetApplicationInfoTool.test.js +8 -5
- package/mcp-server/tools/project/__tests__/GetBuildLogsTool.test.js +3 -1
- package/mcp-server/tools/project/__tests__/GetBuildStatusTool.test.js +3 -1
- package/mcp-server/tools/project/__tests__/GetConfigValuesTool.test.js +7 -3
- package/mcp-server/tools/project/__tests__/GuidedWalkthroughTool.test.js +3 -1
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +17 -3
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +3 -1
- package/mcp-server/utils/__tests__/content.test.js +0 -3
- package/mcp-server/utils/__tests__/feedbackTracking.test.js +0 -3
- package/mcp-server/utils/__tests__/project.test.js +65 -4
- package/mcp-server/utils/project.js +6 -2
- package/package.json +15 -17
- package/types/Cms.d.ts +1 -1
- package/types/Cms.js +2 -0
- package/types/LocalDev.d.ts +3 -2
- package/types/PackageJson.d.ts +10 -0
- package/types/PackageJson.js +1 -0
- package/types/ProjectComponents.d.ts +1 -1
- package/ui/components/BoxWithTitle.js +1 -1
- package/ui/components/Table.d.ts +89 -0
- package/ui/components/Table.js +246 -0
- package/ui/lib/table.d.ts +2 -0
- package/ui/lib/table.js +11 -0
- package/ui/playground/Playground.d.ts +5 -0
- package/ui/{views/UiSandbox.js → playground/Playground.js} +4 -4
- package/ui/{lib/ui-testing-utils.d.ts → playground/fixtures.d.ts} +1 -1
- package/ui/{lib/ui-testing-utils.js → playground/fixtures.js} +33 -1
- package/ui/render.d.ts +19 -0
- package/ui/render.js +44 -0
- package/commands/__tests__/create.test.js +0 -53
- package/commands/create.d.ts +0 -4
- package/commands/create.js +0 -137
- package/commands/customObject/__tests__/schema.test.js +0 -53
- package/commands/customObject/schema/create.d.ts +0 -4
- package/commands/customObject/schema/create.js +0 -34
- package/commands/customObject/schema/delete.d.ts +0 -4
- package/commands/customObject/schema/delete.js +0 -37
- package/commands/customObject/schema/fetch-all.d.ts +0 -4
- package/commands/customObject/schema/fetch-all.js +0 -32
- package/commands/customObject/schema/fetch.d.ts +0 -4
- package/commands/customObject/schema/fetch.js +0 -36
- package/commands/customObject/schema/list.d.ts +0 -4
- package/commands/customObject/schema/list.js +0 -26
- package/commands/customObject/schema/update.d.ts +0 -4
- package/commands/customObject/schema/update.js +0 -39
- package/commands/customObject/schema.d.ts +0 -3
- package/commands/customObject/schema.js +0 -31
- package/commands/fetch.d.ts +0 -4
- package/commands/fetch.js +0 -52
- package/commands/function/deploy.d.ts +0 -4
- package/commands/function/deploy.js +0 -31
- package/commands/function/list.d.ts +0 -4
- package/commands/function/list.js +0 -33
- package/commands/function/server.d.ts +0 -4
- package/commands/function/server.js +0 -57
- package/commands/function.d.ts +0 -3
- package/commands/function.js +0 -32
- package/commands/lint.d.ts +0 -4
- package/commands/lint.js +0 -31
- package/commands/list.d.ts +0 -4
- package/commands/list.js +0 -31
- package/commands/logs.d.ts +0 -4
- package/commands/logs.js +0 -58
- package/commands/module/marketplace-validate.d.ts +0 -4
- package/commands/module/marketplace-validate.js +0 -31
- package/commands/module.d.ts +0 -3
- package/commands/module.js +0 -23
- package/commands/mv.d.ts +0 -4
- package/commands/mv.js +0 -35
- package/commands/project/__tests__/migrateApp.test.js +0 -78
- package/commands/project/migrateApp.d.ts +0 -4
- package/commands/project/migrateApp.js +0 -55
- package/commands/remove.d.ts +0 -4
- package/commands/remove.js +0 -31
- package/commands/theme/generate-selectors.d.ts +0 -4
- package/commands/theme/generate-selectors.js +0 -30
- package/commands/theme/marketplace-validate.d.ts +0 -4
- package/commands/theme/marketplace-validate.js +0 -33
- package/commands/theme/preview.d.ts +0 -4
- package/commands/theme/preview.js +0 -59
- package/commands/theme.d.ts +0 -3
- package/commands/theme.js +0 -29
- package/commands/upload.d.ts +0 -4
- package/commands/upload.js +0 -62
- package/commands/watch.d.ts +0 -4
- package/commands/watch.js +0 -73
- package/lib/__tests__/npm.test.js +0 -57
- package/lib/__tests__/projectProfiles.test.js +0 -129
- package/lib/app/__tests__/migrate_legacy.test.js +0 -143
- package/lib/app/migrate_legacy.d.ts +0 -4
- package/lib/app/migrate_legacy.js +0 -121
- package/lib/npm.js +0 -33
- package/lib/projectProfiles.d.ts +0 -7
- package/lib/projectProfiles.js +0 -73
- package/lib/ui/table.d.ts +0 -3
- package/lib/ui/table.js +0 -63
- package/ui/index.d.ts +0 -1
- package/ui/index.js +0 -6
- package/ui/views/UiSandbox.d.ts +0 -5
- /package/commands/__tests__/{create.test.d.ts → upgrade.test.d.ts} +0 -0
- /package/commands/{customObject/__tests__/schema.test.d.ts → cms/__tests__/upload.test.d.ts} +0 -0
- /package/commands/{project/__tests__/migrateApp.test.d.ts → cms/__tests__/watch.test.d.ts} +0 -0
- /package/{lib/__tests__/npm.test.d.ts → commands/project/__tests__/dev.test.d.ts} +0 -0
- /package/lib/__tests__/{projectProfiles.test.d.ts → cliUpgradeUtils.test.d.ts} +0 -0
- /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,
|
|
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
|
-
|
|
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
|
|
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: '
|
|
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
|
-
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
|
|
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
|
+
});
|
|
@@ -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 (
|
|
44
|
-
uiLogger.error(lib.errorHandlers.index.configTimeoutErrorOccurred(
|
|
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
|
+
}
|