@hubspot/cli 8.0.10-experimental.7 → 8.0.11-experimental.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 (170) hide show
  1. package/bin/cli.js +2 -0
  2. package/commands/account/auth.js +12 -22
  3. package/commands/account/clean.js +5 -6
  4. package/commands/account/createOverride.js +7 -7
  5. package/commands/account/info.js +2 -1
  6. package/commands/account/list.js +3 -5
  7. package/commands/account/remove.js +2 -3
  8. package/commands/account/removeOverride.js +8 -10
  9. package/commands/account/rename.js +5 -6
  10. package/commands/account/use.js +8 -19
  11. package/commands/api.d.ts +10 -0
  12. package/commands/api.js +164 -0
  13. package/commands/app/migrate.js +8 -8
  14. package/commands/app/secret/add.js +6 -7
  15. package/commands/app/secret/delete.js +9 -10
  16. package/commands/app/secret/list.js +6 -7
  17. package/commands/app/secret/update.js +8 -9
  18. package/commands/auth.js +12 -12
  19. package/commands/cms/app/create.js +9 -5
  20. package/commands/cms/convertFields.js +8 -8
  21. package/commands/cms/delete.js +2 -3
  22. package/commands/cms/fetch.js +7 -7
  23. package/commands/cms/function/create.js +9 -5
  24. package/commands/cms/function/deploy.js +2 -3
  25. package/commands/cms/function/list.js +11 -7
  26. package/commands/cms/function/logs.js +17 -23
  27. package/commands/cms/function/server.js +2 -3
  28. package/commands/cms/getReactModule.js +7 -8
  29. package/commands/cms/lighthouseScore.js +25 -24
  30. package/commands/cms/lint.js +4 -5
  31. package/commands/cms/list.js +5 -6
  32. package/commands/cms/module/create.js +9 -5
  33. package/commands/cms/module/marketplace-validate.js +7 -8
  34. package/commands/cms/mv.js +2 -3
  35. package/commands/cms/template/create.js +10 -6
  36. package/commands/cms/theme/create.js +5 -5
  37. package/commands/cms/theme/generate-selectors.js +5 -4
  38. package/commands/cms/theme/marketplace-validate.js +8 -9
  39. package/commands/cms/theme/preview.js +16 -8
  40. package/commands/cms/upload.js +15 -12
  41. package/commands/cms/watch.js +5 -5
  42. package/commands/cms/webpack/create.js +5 -5
  43. package/commands/completion.js +3 -5
  44. package/commands/config/migrate.js +6 -7
  45. package/commands/config/set.js +5 -6
  46. package/commands/customObject/create.js +4 -5
  47. package/commands/customObject/createSchema.js +4 -5
  48. package/commands/customObject/deleteSchema.js +4 -5
  49. package/commands/customObject/fetchAllSchemas.js +2 -3
  50. package/commands/customObject/fetchSchema.js +2 -3
  51. package/commands/customObject/listSchemas.js +2 -3
  52. package/commands/customObject/updateSchema.js +4 -5
  53. package/commands/doctor.js +8 -8
  54. package/commands/feedback.js +6 -4
  55. package/commands/filemanager/fetch.js +5 -6
  56. package/commands/filemanager/upload.js +5 -5
  57. package/commands/getStarted.js +14 -16
  58. package/commands/hubdb/clear.js +5 -6
  59. package/commands/hubdb/create.js +4 -5
  60. package/commands/hubdb/delete.js +8 -9
  61. package/commands/hubdb/fetch.js +5 -6
  62. package/commands/hubdb/list.js +16 -14
  63. package/commands/init.js +14 -17
  64. package/commands/mcp/setup.js +5 -6
  65. package/commands/mcp/start.js +2 -3
  66. package/commands/open.js +4 -5
  67. package/commands/project/add.js +10 -5
  68. package/commands/project/create.js +10 -10
  69. package/commands/project/delete.d.ts +7 -0
  70. package/commands/project/delete.js +74 -0
  71. package/commands/project/deploy.js +36 -34
  72. package/commands/project/dev/deprecatedFlow.js +42 -15
  73. package/commands/project/dev/index.d.ts +3 -3
  74. package/commands/project/dev/index.js +24 -30
  75. package/commands/project/dev/unifiedFlow.js +37 -14
  76. package/commands/project/download.js +10 -11
  77. package/commands/project/info.d.ts +4 -0
  78. package/commands/project/info.js +67 -0
  79. package/commands/project/installDeps.js +9 -6
  80. package/commands/project/lint.js +11 -8
  81. package/commands/project/list.js +14 -14
  82. package/commands/project/listBuilds.js +8 -6
  83. package/commands/project/logs.js +5 -6
  84. package/commands/project/migrate.js +8 -8
  85. package/commands/project/open.js +5 -6
  86. package/commands/project/profile/add.js +12 -8
  87. package/commands/project/profile/delete.js +15 -11
  88. package/commands/project/updateDeps.js +9 -6
  89. package/commands/project/upload.js +31 -17
  90. package/commands/project/validate.js +11 -11
  91. package/commands/project/watch.js +20 -20
  92. package/commands/project.js +4 -0
  93. package/commands/sandbox/create.js +15 -15
  94. package/commands/sandbox/delete.js +13 -14
  95. package/commands/secret/addSecret.js +6 -7
  96. package/commands/secret/deleteSecret.js +5 -6
  97. package/commands/secret/listSecret.js +2 -3
  98. package/commands/secret/updateSecret.js +4 -5
  99. package/commands/testAccount/create.d.ts +1 -1
  100. package/commands/testAccount/create.js +20 -16
  101. package/commands/testAccount/createConfig.js +7 -8
  102. package/commands/testAccount/delete.js +27 -18
  103. package/commands/testAccount/importData.js +6 -7
  104. package/commands/upgrade.js +9 -10
  105. package/lang/en.d.ts +123 -5
  106. package/lang/en.js +121 -6
  107. package/lib/accountAuth.js +2 -2
  108. package/lib/buildAccount.js +3 -3
  109. package/lib/constants.d.ts +0 -1
  110. package/lib/constants.js +0 -1
  111. package/lib/doctor/Diagnosis.js +5 -5
  112. package/lib/errorHandlers/index.js +4 -3
  113. package/lib/errorHandlers/suppressError.js +4 -0
  114. package/lib/errors/PromptExitError.d.ts +4 -2
  115. package/lib/errors/PromptExitError.js +3 -0
  116. package/lib/hasFeature.js +1 -2
  117. package/lib/middleware/autoUpdateMiddleware.js +6 -3
  118. package/lib/process.d.ts +1 -1
  119. package/lib/process.js +10 -3
  120. package/lib/projects/create/v2.js +1 -2
  121. package/lib/projects/delete.d.ts +13 -0
  122. package/lib/projects/delete.js +193 -0
  123. package/lib/projects/localDev/AppDevModeInterface.js +11 -11
  124. package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +3 -1
  125. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +2 -2
  126. package/lib/projects/localDev/DevSessionManager.d.ts +6 -3
  127. package/lib/projects/localDev/DevSessionManager.js +31 -19
  128. package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +3 -0
  129. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +16 -12
  130. package/lib/projects/localDev/LocalDevProcess.js +6 -5
  131. package/lib/projects/localDev/LocalDevState.d.ts +3 -2
  132. package/lib/projects/localDev/LocalDevState.js +3 -1
  133. package/lib/projects/localDev/helpers/account.d.ts +4 -3
  134. package/lib/projects/localDev/helpers/account.js +16 -19
  135. package/lib/projects/localDev/helpers/process.d.ts +1 -1
  136. package/lib/projects/localDev/helpers/process.js +4 -10
  137. package/lib/projects/localDev/helpers/project.d.ts +4 -3
  138. package/lib/projects/localDev/helpers/project.js +31 -15
  139. package/lib/projects/projectInfo.d.ts +5 -0
  140. package/lib/projects/projectInfo.js +82 -0
  141. package/lib/projects/projectProfiles.d.ts +1 -2
  142. package/lib/projects/projectProfiles.js +5 -17
  143. package/lib/projects/upload.js +19 -0
  144. package/lib/projects/workspaces.d.ts +42 -0
  145. package/lib/projects/workspaces.js +350 -0
  146. package/lib/prompts/createApiSamplePrompt.js +4 -0
  147. package/lib/prompts/projectProfilePrompt.d.ts +2 -0
  148. package/lib/prompts/projectProfilePrompt.js +46 -0
  149. package/lib/prompts/promptUtils.js +3 -2
  150. package/lib/prompts/selectHubDBTablePrompt.js +2 -2
  151. package/lib/prompts/selectPublicAppForMigrationPrompt.js +2 -2
  152. package/lib/theme/cmsDevServerProcess.d.ts +2 -0
  153. package/lib/theme/cmsDevServerProcess.js +7 -6
  154. package/lib/ui/SpinniesManager.d.ts +1 -0
  155. package/lib/ui/SpinniesManager.js +20 -6
  156. package/lib/ui/spinniesUtils.d.ts +0 -1
  157. package/lib/ui/spinniesUtils.js +6 -16
  158. package/lib/usageTracking.d.ts +3 -4
  159. package/lib/yargs/makeYargsBuilder.d.ts +13 -0
  160. package/lib/yargs/makeYargsBuilder.js +33 -0
  161. package/lib/yargs/makeYargsHandlerWithUsageTracking.d.ts +3 -0
  162. package/lib/yargs/makeYargsHandlerWithUsageTracking.js +95 -0
  163. package/lib/yargs/strictEnforceBoolean.d.ts +1 -0
  164. package/lib/yargs/strictEnforceBoolean.js +13 -0
  165. package/lib/yargsUtils.d.ts +3 -16
  166. package/lib/yargsUtils.js +3 -48
  167. package/package.json +5 -4
  168. package/types/LocalDev.d.ts +5 -0
  169. package/types/Projects.d.ts +19 -0
  170. package/types/Yargs.d.ts +18 -1
package/bin/cli.js CHANGED
@@ -31,6 +31,7 @@ import testAccountCommands from '../commands/testAccount.js';
31
31
  import getStartedCommand from '../commands/getStarted.js';
32
32
  import mcpCommand from '../commands/mcp.js';
33
33
  import upgradeCommand from '../commands/upgrade.js';
34
+ import apiCommand from '../commands/api.js';
34
35
  import { uiLogger } from '../lib/ui/logger.js';
35
36
  import { initializeSpinniesManager } from '../lib/middleware/spinniesMiddleware.js';
36
37
  import { addCommandSuggestions } from '../lib/commandSuggestion.js';
@@ -111,6 +112,7 @@ const argv = yargs(process.argv.slice(2))
111
112
  .command(hubdbCommand)
112
113
  .command(filemanagerCommand)
113
114
  // Misc commands
115
+ .command(apiCommand)
114
116
  .command(customObjectCommand)
115
117
  .command(completionCommand)
116
118
  .command(doctorCommand)
@@ -2,15 +2,15 @@ import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
2
2
  import { PERSONAL_ACCESS_KEY_AUTH_METHOD } from '@hubspot/local-dev-lib/constants/auth';
3
3
  import { deleteConfigFileIfEmpty } from '@hubspot/local-dev-lib/config';
4
4
  import { handleExit } from '../../lib/process.js';
5
- import { trackCommandUsage, trackAuthAction } from '../../lib/usageTracking.js';
5
+ import { trackAuthAction } from '../../lib/usageTracking.js';
6
6
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
7
7
  import { uiFeatureHighlight } from '../../lib/ui/index.js';
8
8
  import { parseStringToNumber } from '../../lib/parsing.js';
9
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
9
10
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
10
11
  import { commands } from '../../lang/en.js';
11
12
  import { uiLogger } from '../../lib/ui/logger.js';
12
13
  import { authenticateNewAccount } from '../../lib/accountAuth.js';
13
- import { PromptExitError } from '../../lib/errors/PromptExitError.js';
14
14
  const TRACKING_STATUS = {
15
15
  STARTED: 'started',
16
16
  ERROR: 'error',
@@ -20,7 +20,7 @@ const authType = PERSONAL_ACCESS_KEY_AUTH_METHOD.value;
20
20
  const describe = commands.account.subcommands.auth.describe;
21
21
  const command = 'auth';
22
22
  async function handler(args) {
23
- const { disableTracking, personalAccessKey: providedPersonalAccessKey, userProvidedAccount, } = args;
23
+ const { disableTracking, personalAccessKey: providedPersonalAccessKey, userProvidedAccount, exit, } = args;
24
24
  let parsedUserProvidedAccountId;
25
25
  if (userProvidedAccount) {
26
26
  try {
@@ -28,33 +28,23 @@ async function handler(args) {
28
28
  }
29
29
  catch (err) {
30
30
  uiLogger.error(commands.account.subcommands.auth.errors.invalidAccountIdProvided);
31
- process.exit(EXIT_CODES.ERROR);
31
+ return exit(EXIT_CODES.ERROR);
32
32
  }
33
33
  }
34
34
  if (!disableTracking) {
35
- trackCommandUsage('account-auth', {}, parsedUserProvidedAccountId);
36
35
  await trackAuthAction('account-auth', authType, TRACKING_STATUS.STARTED);
37
36
  }
38
37
  handleExit(deleteConfigFileIfEmpty);
39
- let updatedConfig;
40
- try {
41
- updatedConfig = await authenticateNewAccount({
42
- env: args.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD,
43
- providedPersonalAccessKey,
44
- accountId: parsedUserProvidedAccountId,
45
- });
46
- }
47
- catch (e) {
48
- if (e instanceof PromptExitError) {
49
- process.exit(e.exitCode);
50
- }
51
- throw e;
52
- }
38
+ const updatedConfig = await authenticateNewAccount({
39
+ env: args.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD,
40
+ providedPersonalAccessKey,
41
+ accountId: parsedUserProvidedAccountId,
42
+ });
53
43
  if (!updatedConfig) {
54
44
  if (!disableTracking) {
55
45
  await trackAuthAction('account-auth', authType, TRACKING_STATUS.ERROR);
56
46
  }
57
- return process.exit(EXIT_CODES.ERROR);
47
+ return exit(EXIT_CODES.ERROR);
58
48
  }
59
49
  const { accountId } = updatedConfig;
60
50
  uiFeatureHighlight([
@@ -66,7 +56,7 @@ async function handler(args) {
66
56
  if (!disableTracking) {
67
57
  await trackAuthAction('account-auth', authType, TRACKING_STATUS.COMPLETE, accountId);
68
58
  }
69
- process.exit(EXIT_CODES.SUCCESS);
59
+ return exit(EXIT_CODES.SUCCESS);
70
60
  }
71
61
  function accountAuthBuilder(yargs) {
72
62
  yargs.options({
@@ -96,7 +86,7 @@ const builder = makeYargsBuilder(accountAuthBuilder, command, commands.account.s
96
86
  const accountAuthCommand = {
97
87
  command,
98
88
  describe,
99
- handler,
89
+ handler: makeYargsHandlerWithUsageTracking('account-auth', handler),
100
90
  builder,
101
91
  };
102
92
  export default accountAuthCommand;
@@ -3,12 +3,12 @@ import { accessTokenForPersonalAccessKey } from '@hubspot/local-dev-lib/personal
3
3
  import { removeAccountFromConfig, getAllConfigAccounts, getConfigDefaultAccountIfExists, setConfigAccountAsDefault, } from '@hubspot/local-dev-lib/config';
4
4
  import { getDefaultAccountOverrideAccountId, getDefaultAccountOverrideFilePath, } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
5
5
  import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
6
- import { trackCommandUsage } from '../../lib/usageTracking.js';
7
6
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
8
7
  import { promptUser } from '../../lib/prompts/promptUtils.js';
9
8
  import { selectAccountFromConfig } from '../../lib/prompts/accountsPrompt.js';
10
9
  import SpinniesManager from '../../lib/ui/SpinniesManager.js';
11
10
  import { uiAccountDescription } from '../../lib/ui/index.js';
11
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
12
12
  import { logError } from '../../lib/errorHandlers/index.js';
13
13
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
14
14
  import { commands } from '../../lang/en.js';
@@ -17,13 +17,12 @@ import { renderList } from '../../ui/render.js';
17
17
  const command = 'clean';
18
18
  const describe = commands.account.subcommands.clean.describe;
19
19
  async function handler(args) {
20
- const { qa } = args;
21
- trackCommandUsage('accounts-clean');
20
+ const { qa, exit } = args;
22
21
  const accountsList = getAllConfigAccounts();
23
22
  const filteredTestAccounts = accountsList.filter(p => qa ? p.env === 'qa' : p.env !== 'qa');
24
23
  if (filteredTestAccounts && filteredTestAccounts.length === 0) {
25
24
  uiLogger.log(commands.account.subcommands.clean.noResults);
26
- process.exit(EXIT_CODES.SUCCESS);
25
+ return exit(EXIT_CODES.SUCCESS);
27
26
  }
28
27
  const accountsToRemove = [];
29
28
  SpinniesManager.init({
@@ -105,7 +104,7 @@ async function handler(args) {
105
104
  });
106
105
  }
107
106
  uiLogger.log('');
108
- process.exit(EXIT_CODES.SUCCESS);
107
+ return exit(EXIT_CODES.SUCCESS);
109
108
  }
110
109
  function accountCleanBuilder(yargs) {
111
110
  yargs.example([['$0 accounts clean']]);
@@ -119,7 +118,7 @@ const builder = makeYargsBuilder(accountCleanBuilder, command, describe, {
119
118
  const accountCleanCommand = {
120
119
  command,
121
120
  describe,
122
- handler,
121
+ handler: makeYargsHandlerWithUsageTracking('accounts-clean', handler),
123
122
  builder,
124
123
  };
125
124
  export default accountCleanCommand;
@@ -6,20 +6,21 @@ import { getConfigFilePath, getConfigAccountIfExists, globalConfigFileExists, ge
6
6
  import { getDefaultAccountOverrideAccountId, getDefaultAccountOverrideFilePath, } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
7
7
  import { promptUser } from '../../lib/prompts/promptUtils.js';
8
8
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
9
- import { trackCommandUsage } from '../../lib/usageTracking.js';
10
9
  import { selectAccountFromConfig } from '../../lib/prompts/accountsPrompt.js';
11
10
  import { logError } from '../../lib/errorHandlers/index.js';
11
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
12
12
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
13
13
  import { commands } from '../../lang/en.js';
14
14
  import { uiLogger } from '../../lib/ui/logger.js';
15
15
  const command = 'create-override [account]';
16
16
  const describe = commands.account.subcommands.createOverride.describe(DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME);
17
17
  async function handler(args) {
18
+ const { exit } = args;
18
19
  let overrideDefaultAccount = args.account;
19
20
  const globalConfigExists = globalConfigFileExists();
20
21
  if (!globalConfigExists) {
21
22
  uiLogger.error(commands.account.subcommands.createOverride.errors.globalConfigNotFound);
22
- process.exit(EXIT_CODES.ERROR);
23
+ return exit(EXIT_CODES.ERROR);
23
24
  }
24
25
  const accounts = getAllConfigAccounts();
25
26
  const accountOverrideId = getDefaultAccountOverrideAccountId(accounts);
@@ -33,7 +34,7 @@ async function handler(args) {
33
34
  });
34
35
  uiLogger.log('');
35
36
  if (!replaceOverrideFile) {
36
- process.exit(EXIT_CODES.SUCCESS);
37
+ return exit(EXIT_CODES.SUCCESS);
37
38
  }
38
39
  }
39
40
  if (!overrideDefaultAccount) {
@@ -48,16 +49,15 @@ async function handler(args) {
48
49
  }
49
50
  const account = getConfigAccountIfExists(overrideDefaultAccount);
50
51
  const accountId = account?.accountId;
51
- trackCommandUsage('account-createOverride', undefined, accountId);
52
52
  try {
53
53
  const overrideFilePath = path.join(getCwd(), DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME);
54
54
  await fs.writeFile(overrideFilePath, accountId.toString(), 'utf8');
55
55
  uiLogger.success(commands.account.subcommands.createOverride.success(overrideFilePath));
56
- process.exit(EXIT_CODES.SUCCESS);
56
+ return exit(EXIT_CODES.SUCCESS);
57
57
  }
58
58
  catch (e) {
59
59
  logError(e);
60
- process.exit(EXIT_CODES.ERROR);
60
+ return exit(EXIT_CODES.ERROR);
61
61
  }
62
62
  }
63
63
  function accountCreateOverrideBuilder(yargs) {
@@ -87,7 +87,7 @@ const builder = makeYargsBuilder(accountCreateOverrideBuilder, command, describe
87
87
  const accountCreateOverrideCommand = {
88
88
  command,
89
89
  describe,
90
- handler,
90
+ handler: makeYargsHandlerWithUsageTracking('account-createOverride', handler),
91
91
  builder,
92
92
  };
93
93
  export default accountCreateOverrideCommand;
@@ -3,6 +3,7 @@ import { getDefaultAccountOverrideFilePath } from '@hubspot/local-dev-lib/config
3
3
  import { getAccessToken } from '@hubspot/local-dev-lib/personalAccessKey';
4
4
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
5
5
  import { indent } from '../../lib/ui/index.js';
6
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
6
7
  import { commands } from '../../lang/en.js';
7
8
  import { uiLogger } from '../../lib/ui/logger.js';
8
9
  import { renderList } from '../../ui/render.js';
@@ -69,7 +70,7 @@ const builder = makeYargsBuilder(accountInfoBuilder, command, describe, {
69
70
  const accountInfoCommand = {
70
71
  command,
71
72
  describe,
72
- handler,
73
+ handler: makeYargsHandlerWithUsageTracking('account-info', handler),
73
74
  builder,
74
75
  };
75
76
  export default accountInfoCommand;
@@ -1,9 +1,9 @@
1
1
  import { getConfigFilePath, getAllConfigAccounts, getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
2
2
  import { getDefaultAccountOverrideFilePath } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
3
3
  import { indent } from '../../lib/ui/index.js';
4
- import { trackCommandUsage } from '../../lib/usageTracking.js';
5
4
  import { isSandbox, isDeveloperTestAccount } from '../../lib/accountTypes.js';
6
5
  import { HUBSPOT_ACCOUNT_TYPES, HUBSPOT_ACCOUNT_TYPE_STRINGS, } from '@hubspot/local-dev-lib/constants/config';
6
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
7
7
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
8
8
  import { uiLogger } from '../../lib/ui/logger.js';
9
9
  import { commands } from '../../lang/en.js';
@@ -58,9 +58,7 @@ function getAccountData(mappedAccountData) {
58
58
  });
59
59
  return accountData;
60
60
  }
61
- async function handler(args) {
62
- const { derivedAccountId } = args;
63
- trackCommandUsage('accounts-list', undefined, derivedAccountId);
61
+ async function handler() {
64
62
  const configPath = getConfigFilePath();
65
63
  const accountsList = getAllConfigAccounts();
66
64
  const mappedAccountData = sortAndMapAccounts(accountsList);
@@ -101,7 +99,7 @@ const builder = makeYargsBuilder(accountListBuilder, command, describe, {
101
99
  const accountListCommand = {
102
100
  command,
103
101
  describe,
104
- handler,
102
+ handler: makeYargsHandlerWithUsageTracking('accounts-list', handler),
105
103
  builder,
106
104
  };
107
105
  export default accountListCommand;
@@ -1,10 +1,10 @@
1
1
  import fs from 'fs';
2
2
  import { getConfigFilePath, removeAccountFromConfig, getConfigDefaultAccountIfExists, getConfigAccountIfExists, getConfigAccountById, setConfigAccountAsDefault, getAllConfigAccounts, } from '@hubspot/local-dev-lib/config';
3
3
  import { getDefaultAccountOverrideAccountId, getDefaultAccountOverrideFilePath, } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
4
- import { trackCommandUsage } from '../../lib/usageTracking.js';
5
4
  import { promptUser } from '../../lib/prompts/promptUtils.js';
6
5
  import { logError } from '../../lib/errorHandlers/index.js';
7
6
  import { selectAccountFromConfig } from '../../lib/prompts/accountsPrompt.js';
7
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
8
8
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
9
9
  import { uiLogger } from '../../lib/ui/logger.js';
10
10
  import { commands } from '../../lang/en.js';
@@ -23,7 +23,6 @@ async function handler(args) {
23
23
  accountToRemoveId = await selectAccountFromConfig(commands.account.subcommands.remove.prompts.selectAccountToRemove);
24
24
  }
25
25
  accountToRemoveConfig = getConfigAccountById(accountToRemoveId);
26
- trackCommandUsage('accounts-remove', undefined, accountToRemoveId);
27
26
  const currentDefaultAccount = getConfigDefaultAccountIfExists();
28
27
  const accounts = getAllConfigAccounts();
29
28
  const accountOverride = getDefaultAccountOverrideAccountId(accounts);
@@ -81,7 +80,7 @@ const builder = makeYargsBuilder(accountRemoveBuilder, command, describe, {
81
80
  const accountRemoveCommand = {
82
81
  command,
83
82
  describe,
84
- handler,
83
+ handler: makeYargsHandlerWithUsageTracking('accounts-remove', handler),
85
84
  builder,
86
85
  };
87
86
  export default accountRemoveCommand;
@@ -3,27 +3,25 @@ import { globalConfigFileExists, getAllConfigAccounts, } from '@hubspot/local-de
3
3
  import { getDefaultAccountOverrideAccountId, getDefaultAccountOverrideFilePath, } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
4
4
  import { DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME } from '@hubspot/local-dev-lib/constants/config';
5
5
  import { promptUser } from '../../lib/prompts/promptUtils.js';
6
- import { trackCommandUsage } from '../../lib/usageTracking.js';
7
6
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
8
7
  import { logError } from '../../lib/errorHandlers/index.js';
8
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
9
9
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
10
10
  import { uiLogger } from '../../lib/ui/logger.js';
11
11
  import { commands } from '../../lang/en.js';
12
12
  const command = 'remove-override';
13
13
  const describe = commands.account.subcommands.removeOverride.describe(DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME);
14
14
  async function handler(args) {
15
- const { force } = args;
15
+ const { force, exit } = args;
16
16
  const globalConfigExists = globalConfigFileExists();
17
17
  if (!globalConfigExists) {
18
18
  uiLogger.error(commands.account.subcommands.removeOverride.errors.globalConfigNotFound);
19
- process.exit(EXIT_CODES.ERROR);
19
+ return exit(EXIT_CODES.ERROR);
20
20
  }
21
21
  const accounts = getAllConfigAccounts();
22
22
  const accountOverride = getDefaultAccountOverrideAccountId(accounts);
23
23
  const overrideFilePath = getDefaultAccountOverrideFilePath();
24
24
  if (accountOverride && overrideFilePath) {
25
- const accountId = accountOverride;
26
- trackCommandUsage('account-removeOverride', undefined, accountId);
27
25
  if (!force) {
28
26
  uiLogger.log(commands.account.subcommands.removeOverride.accountOverride(overrideFilePath, accountOverride.toString()));
29
27
  const { deleteOverrideFile } = await promptUser({
@@ -34,22 +32,22 @@ async function handler(args) {
34
32
  });
35
33
  uiLogger.log('');
36
34
  if (!deleteOverrideFile) {
37
- process.exit(EXIT_CODES.SUCCESS);
35
+ return exit(EXIT_CODES.SUCCESS);
38
36
  }
39
37
  }
40
38
  try {
41
39
  fs.unlinkSync(overrideFilePath);
42
40
  uiLogger.success(commands.account.subcommands.removeOverride.success);
43
- process.exit(EXIT_CODES.SUCCESS);
41
+ return exit(EXIT_CODES.SUCCESS);
44
42
  }
45
43
  catch (error) {
46
44
  logError(error);
47
- process.exit(EXIT_CODES.ERROR);
45
+ return exit(EXIT_CODES.ERROR);
48
46
  }
49
47
  }
50
48
  else {
51
49
  uiLogger.log(commands.account.subcommands.removeOverride.noOverrideFile);
52
- process.exit(EXIT_CODES.SUCCESS);
50
+ return exit(EXIT_CODES.SUCCESS);
53
51
  }
54
52
  }
55
53
  function accountRemoveOverrideBuilder(yargs) {
@@ -65,7 +63,7 @@ const builder = makeYargsBuilder(accountRemoveOverrideBuilder, command, describe
65
63
  const accountRemoveOverrideCommand = {
66
64
  command,
67
65
  describe,
68
- handler,
66
+ handler: makeYargsHandlerWithUsageTracking('account-removeOverride', handler),
69
67
  builder,
70
68
  };
71
69
  export default accountRemoveOverrideCommand;
@@ -1,7 +1,7 @@
1
1
  import { renameConfigAccount } from '@hubspot/local-dev-lib/config';
2
- import { trackCommandUsage } from '../../lib/usageTracking.js';
3
2
  import { commands } from '../../lang/en.js';
4
3
  import { uiLogger } from '../../lib/ui/logger.js';
4
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
5
5
  import { logError } from '../../lib/errorHandlers/index.js';
6
6
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
7
7
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
@@ -9,8 +9,7 @@ import { toKebabCase } from '@hubspot/local-dev-lib/text';
9
9
  const command = 'rename <account-name> <new-name>';
10
10
  const describe = commands.account.subcommands.rename.describe;
11
11
  async function handler(args) {
12
- const { accountName, newName, derivedAccountId } = args;
13
- trackCommandUsage('accounts-rename', undefined, derivedAccountId);
12
+ const { accountName, newName, exit } = args;
14
13
  const newNameKebabCase = toKebabCase(newName);
15
14
  const nameWasSanitized = newNameKebabCase !== newName;
16
15
  try {
@@ -18,10 +17,10 @@ async function handler(args) {
18
17
  }
19
18
  catch (error) {
20
19
  logError(error);
21
- process.exit(EXIT_CODES.ERROR);
20
+ return exit(EXIT_CODES.ERROR);
22
21
  }
23
22
  uiLogger.success(commands.account.subcommands.rename.success.renamed(accountName, newNameKebabCase, nameWasSanitized));
24
- process.exit(EXIT_CODES.SUCCESS);
23
+ return exit(EXIT_CODES.SUCCESS);
25
24
  }
26
25
  function accountRenameBuilder(yargs) {
27
26
  yargs.positional('account-name', {
@@ -45,7 +44,7 @@ const builder = makeYargsBuilder(accountRenameBuilder, command, describe, {
45
44
  const accountRenameCommand = {
46
45
  command,
47
46
  describe,
48
- handler,
47
+ handler: makeYargsHandlerWithUsageTracking('accounts-rename', handler),
49
48
  builder,
50
49
  };
51
50
  export default accountRenameCommand;
@@ -1,17 +1,17 @@
1
1
  import { getConfigFilePath, setConfigAccountAsDefault, getConfigAccountIfExists, getConfigAccountByName, getConfigAccountById, globalConfigFileExists, getAllConfigAccounts, } from '@hubspot/local-dev-lib/config';
2
2
  import { getDefaultAccountOverrideAccountId, getDefaultAccountOverrideFilePath, } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
3
3
  import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
4
- import { trackCommandUsage } from '../../lib/usageTracking.js';
5
4
  import { commands } from '../../lang/en.js';
6
5
  import { uiLogger } from '../../lib/ui/logger.js';
7
6
  import { selectAccountFromConfig, AUTHENTICATE_NEW_ACCOUNT_VALUE, } from '../../lib/prompts/accountsPrompt.js';
7
+ import { makeYargsHandlerWithUsageTracking } from '../../lib/yargs/makeYargsHandlerWithUsageTracking.js';
8
8
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
9
9
  import { authenticateNewAccount } from '../../lib/accountAuth.js';
10
- import { PromptExitError } from '../../lib/errors/PromptExitError.js';
11
10
  import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
12
11
  const command = 'use [account]';
13
12
  const describe = commands.account.subcommands.use.describe;
14
13
  async function handler(args) {
14
+ const { exit } = args;
15
15
  let newDefaultAccount = args.account;
16
16
  const usingGlobalConfig = globalConfigFileExists();
17
17
  if (!newDefaultAccount) {
@@ -25,23 +25,13 @@ async function handler(args) {
25
25
  }
26
26
  }
27
27
  if (newDefaultAccount === AUTHENTICATE_NEW_ACCOUNT_VALUE) {
28
- let updatedConfig;
29
- try {
30
- updatedConfig = await authenticateNewAccount({
31
- env: args.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD,
32
- setAsDefaultAccount: true,
33
- });
34
- }
35
- catch (e) {
36
- if (e instanceof PromptExitError) {
37
- process.exit(e.exitCode);
38
- }
39
- throw e;
40
- }
28
+ const updatedConfig = await authenticateNewAccount({
29
+ env: args.qa ? ENVIRONMENTS.QA : ENVIRONMENTS.PROD,
30
+ setAsDefaultAccount: true,
31
+ });
41
32
  if (!updatedConfig) {
42
- process.exit(EXIT_CODES.ERROR);
33
+ return exit(EXIT_CODES.ERROR);
43
34
  }
44
- trackCommandUsage('accounts-use', undefined, updatedConfig.accountId);
45
35
  return;
46
36
  }
47
37
  let account;
@@ -51,7 +41,6 @@ async function handler(args) {
51
41
  else {
52
42
  account = getConfigAccountByName(String(newDefaultAccount));
53
43
  }
54
- trackCommandUsage('accounts-use', undefined, account?.accountId);
55
44
  const accounts = getAllConfigAccounts();
56
45
  const accountOverride = getDefaultAccountOverrideAccountId(accounts);
57
46
  const overrideFilePath = getDefaultAccountOverrideFilePath();
@@ -87,7 +76,7 @@ const builder = makeYargsBuilder(accountUseBuilder, command, describe, {
87
76
  const accountUseCommand = {
88
77
  command,
89
78
  describe,
90
- handler,
79
+ handler: makeYargsHandlerWithUsageTracking('accounts-use', handler),
91
80
  builder,
92
81
  };
93
82
  export default accountUseCommand;
@@ -0,0 +1,10 @@
1
+ import { CommonArgs, ConfigArgs, EnvironmentArgs, AccountArgs, JSONOutputArgs, YargsCommandModule } from '../types/Yargs.js';
2
+ declare const HTTP_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE"];
3
+ type HttpMethod = (typeof HTTP_METHODS)[number];
4
+ export type ApiArgs = CommonArgs & ConfigArgs & EnvironmentArgs & AccountArgs & JSONOutputArgs & {
5
+ endpoint: string;
6
+ method?: HttpMethod;
7
+ data?: string;
8
+ };
9
+ declare const apiCommand: YargsCommandModule<unknown, ApiArgs>;
10
+ export default apiCommand;
@@ -0,0 +1,164 @@
1
+ import { http } from '@hubspot/local-dev-lib/http';
2
+ import { getHubSpotApiOrigin } from '@hubspot/local-dev-lib/urls';
3
+ import { getConfigAccountEnvironment } from '@hubspot/local-dev-lib/config';
4
+ import { logError, debugError, ApiErrorContext, } from '../lib/errorHandlers/index.js';
5
+ import { isHubSpotHttpError } from '@hubspot/local-dev-lib/errors/index';
6
+ import { commands } from '../lang/en.js';
7
+ import { EXIT_CODES } from '../lib/enums/exitCodes.js';
8
+ import { makeYargsHandlerWithUsageTracking } from '../lib/yargs/makeYargsHandlerWithUsageTracking.js';
9
+ import { makeYargsBuilder } from '../lib/yargsUtils.js';
10
+ import { uiLogger } from '../lib/ui/logger.js';
11
+ const HTTP_METHODS = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'];
12
+ const command = 'api <endpoint>';
13
+ const describe = commands.api.describe;
14
+ function parseRequestData(data) {
15
+ try {
16
+ return JSON.parse(data);
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ function resolveMethod(args) {
23
+ if (args.method) {
24
+ return args.method;
25
+ }
26
+ return args.data ? 'POST' : 'GET';
27
+ }
28
+ function normalizeEndpoint(endpoint) {
29
+ return endpoint.startsWith('/') ? endpoint.slice(1) : endpoint;
30
+ }
31
+ async function handler(args) {
32
+ const { endpoint, data, derivedAccountId, json: formatOutputAsJson, exit, addUsageMetadata, } = args;
33
+ const method = resolveMethod(args);
34
+ addUsageMetadata({ action: method });
35
+ let parsedData;
36
+ if (data) {
37
+ parsedData = parseRequestData(data);
38
+ if (parsedData === undefined) {
39
+ uiLogger.error(commands.api.errors.invalidJson);
40
+ return exit(EXIT_CODES.ERROR);
41
+ }
42
+ }
43
+ const normalizedEndpoint = normalizeEndpoint(endpoint);
44
+ const env = getConfigAccountEnvironment(derivedAccountId);
45
+ const baseUrl = getHubSpotApiOrigin(env);
46
+ const fullUrl = `${baseUrl}/${normalizedEndpoint}`;
47
+ if (!formatOutputAsJson) {
48
+ uiLogger.log(commands.api.requestLog(method, fullUrl));
49
+ if (parsedData) {
50
+ uiLogger.log(commands.api.requestBodyLog(JSON.stringify(parsedData)));
51
+ }
52
+ uiLogger.log('');
53
+ }
54
+ try {
55
+ const requestOptions = {
56
+ url: normalizedEndpoint,
57
+ };
58
+ if (parsedData) {
59
+ requestOptions.data = parsedData;
60
+ requestOptions.headers = { 'Content-Type': 'application/json' };
61
+ }
62
+ let response;
63
+ switch (method) {
64
+ case 'GET':
65
+ response = await http.get(derivedAccountId, requestOptions);
66
+ break;
67
+ case 'POST':
68
+ response = await http.post(derivedAccountId, requestOptions);
69
+ break;
70
+ case 'PUT':
71
+ response = await http.put(derivedAccountId, requestOptions);
72
+ break;
73
+ case 'PATCH':
74
+ response = await http.patch(derivedAccountId, requestOptions);
75
+ break;
76
+ case 'DELETE':
77
+ response = await http.delete(derivedAccountId, requestOptions);
78
+ break;
79
+ }
80
+ if (response !== undefined) {
81
+ const responseData = response.data;
82
+ if (formatOutputAsJson) {
83
+ uiLogger.json(responseData);
84
+ }
85
+ else {
86
+ uiLogger.log(commands.api.responseLog);
87
+ uiLogger.log(JSON.stringify(responseData, null, 2));
88
+ }
89
+ }
90
+ }
91
+ catch (error) {
92
+ const errorContext = new ApiErrorContext({
93
+ accountId: derivedAccountId,
94
+ request: `api ${method} ${endpoint}`,
95
+ });
96
+ if (!isHubSpotHttpError(error)) {
97
+ logError(error, errorContext);
98
+ return exit(EXIT_CODES.ERROR);
99
+ }
100
+ debugError(error, errorContext);
101
+ const errorData = error.data;
102
+ if (formatOutputAsJson && errorData) {
103
+ uiLogger.json(errorData);
104
+ }
105
+ else if (errorData) {
106
+ if (error.status && error.statusText) {
107
+ uiLogger.error(commands.api.errors.statusLine(error.status, error.statusText));
108
+ }
109
+ uiLogger.log(JSON.stringify(errorData, null, 2));
110
+ }
111
+ else {
112
+ if (error.status && error.statusText) {
113
+ uiLogger.error(commands.api.errors.statusLine(error.status, error.statusText));
114
+ }
115
+ uiLogger.error(error.message);
116
+ }
117
+ return exit(EXIT_CODES.ERROR);
118
+ }
119
+ return exit(EXIT_CODES.SUCCESS);
120
+ }
121
+ function apiBuilder(yargs) {
122
+ yargs.positional('endpoint', {
123
+ describe: commands.api.positionals.endpoint.describe,
124
+ type: 'string',
125
+ });
126
+ yargs.option('method', {
127
+ alias: 'X',
128
+ describe: commands.api.options.method.describe,
129
+ type: 'string',
130
+ choices: [...HTTP_METHODS, ...HTTP_METHODS.map(m => m.toLowerCase())],
131
+ coerce: (value) => value.toUpperCase(),
132
+ });
133
+ yargs.option('data', {
134
+ describe: commands.api.options.data.describe,
135
+ type: 'string',
136
+ });
137
+ yargs.example([
138
+ ['$0 api /crm/v3/objects/contacts', 'Fetch contacts using GET'],
139
+ [
140
+ '$0 api /crm/v3/objects/contacts -X POST --data \'{"properties":{"email":"test@example.com"}}\'',
141
+ 'Create a contact',
142
+ ],
143
+ ['$0 api /crm/v3/objects/deals/123', 'Fetch a specific deal'],
144
+ [
145
+ '$0 api /crm/v3/objects/contacts -a my-sandbox',
146
+ 'Fetch contacts from a specific account',
147
+ ],
148
+ ]);
149
+ return yargs;
150
+ }
151
+ const builder = makeYargsBuilder(apiBuilder, command, commands.api.verboseDescribe, {
152
+ useGlobalOptions: true,
153
+ useConfigOptions: true,
154
+ useAccountOptions: true,
155
+ useEnvironmentOptions: true,
156
+ useJSONOutputOptions: true,
157
+ });
158
+ const apiCommand = {
159
+ command,
160
+ describe,
161
+ builder,
162
+ handler: makeYargsHandlerWithUsageTracking('api', handler),
163
+ };
164
+ export default apiCommand;