@hubspot/cli 7.7.16-experimental.2 → 7.7.16-experimental.4

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 (45) hide show
  1. package/commands/account/auth.js +3 -3
  2. package/commands/app/install.d.ts +8 -0
  3. package/commands/app/install.js +91 -0
  4. package/commands/app.js +6 -1
  5. package/commands/auth.js +23 -25
  6. package/commands/getStarted.js +2 -2
  7. package/commands/init.js +29 -31
  8. package/commands/project/cloneApp.js +4 -4
  9. package/commands/project/create.js +9 -9
  10. package/commands/project/dev/deprecatedFlow.js +4 -4
  11. package/commands/project/dev/index.js +5 -5
  12. package/commands/project/dev/unifiedFlow.js +1 -0
  13. package/commands/sandbox/delete.js +5 -5
  14. package/commands/testAccount/create.js +31 -2
  15. package/lang/en.d.ts +48 -9
  16. package/lang/en.js +48 -9
  17. package/lib/app/migrate_legacy.js +2 -3
  18. package/lib/middleware/__test__/configMiddleware.test.js +2 -2
  19. package/lib/middleware/configMiddleware.js +10 -2
  20. package/lib/parsing.d.ts +1 -0
  21. package/lib/parsing.js +11 -0
  22. package/lib/polling.d.ts +1 -1
  23. package/lib/polling.js +11 -1
  24. package/lib/projects/add/v3AddComponent.js +4 -0
  25. package/lib/projects/create/index.d.ts +3 -2
  26. package/lib/projects/create/index.js +11 -5
  27. package/lib/projects/create/v3.d.ts +3 -3
  28. package/lib/projects/create/v3.js +2 -2
  29. package/lib/projects/localDev/LocalDevProcess.d.ts +3 -2
  30. package/lib/projects/localDev/LocalDevProcess.js +16 -12
  31. package/lib/projects/localDev/LocalDevState.d.ts +10 -5
  32. package/lib/projects/localDev/LocalDevState.js +18 -20
  33. package/lib/projects/localDev/LocalDevWatcher.js +1 -1
  34. package/lib/prompts/personalAccessKeyPrompt.js +2 -2
  35. package/lib/prompts/projectNameAndDestPrompt.d.ts +3 -0
  36. package/lib/prompts/projectNameAndDestPrompt.js +60 -0
  37. package/lib/prompts/selectProjectTemplatePrompt.d.ts +26 -0
  38. package/lib/prompts/{createProjectPrompt.js → selectProjectTemplatePrompt.js} +6 -55
  39. package/lib/validation.d.ts +1 -1
  40. package/lib/validation.js +4 -4
  41. package/mcp-server/tools/project/CreateProjectTool.d.ts +2 -2
  42. package/package.json +3 -3
  43. package/types/LocalDev.d.ts +1 -0
  44. package/types/Yargs.d.ts +1 -1
  45. package/lib/prompts/createProjectPrompt.d.ts +0 -28
@@ -15,6 +15,9 @@ const usageTracking_1 = require("../../lib/usageTracking");
15
15
  const validation_1 = require("../../lib/validation");
16
16
  const en_1 = require("../../lang/en");
17
17
  const createDeveloperTestAccountConfigPrompt_1 = require("../../lib/prompts/createDeveloperTestAccountConfigPrompt");
18
+ const errorHandlers_1 = require("../../lib/errorHandlers");
19
+ const polling_1 = require("../../lib/polling");
20
+ const SpinniesManager_1 = __importDefault(require("../../lib/ui/SpinniesManager"));
18
21
  const command = 'create';
19
22
  const describe = en_1.commands.testAccount.create.describe;
20
23
  async function handler(args) {
@@ -62,6 +65,13 @@ async function handler(args) {
62
65
  testAccountConfig = await (0, createDeveloperTestAccountConfigPrompt_1.createDeveloperTestAccountConfigPrompt)();
63
66
  }
64
67
  const jsonOutput = {};
68
+ let testAccountId;
69
+ SpinniesManager_1.default.init({
70
+ succeedColor: 'white',
71
+ });
72
+ SpinniesManager_1.default.add('createTestAccount', {
73
+ text: en_1.commands.testAccount.create.polling.start(testAccountConfig.accountName),
74
+ });
65
75
  try {
66
76
  const { data } = await (0, developerTestAccounts_1.createDeveloperTestAccount)(derivedAccountId, testAccountConfig);
67
77
  if (formatOutputAsJson) {
@@ -69,12 +79,31 @@ async function handler(args) {
69
79
  jsonOutput.accountId = data.id;
70
80
  jsonOutput.personalAccessKey = data.personalAccessKey;
71
81
  }
72
- logger_1.uiLogger.success(en_1.commands.testAccount.create.success.configFileUpdated(data.accountName, data.id));
82
+ testAccountId = data.id;
73
83
  }
74
84
  catch (err) {
75
- logger_1.uiLogger.error(en_1.commands.testAccount.create.errors.failedToCreate);
85
+ (0, errorHandlers_1.logError)(err);
76
86
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
77
87
  }
88
+ SpinniesManager_1.default.update('createTestAccount', {
89
+ text: en_1.commands.testAccount.create.polling.syncing,
90
+ });
91
+ try {
92
+ await (0, polling_1.poll)(() => (0, developerTestAccounts_1.fetchDeveloperTestAccountGateSyncStatus)(derivedAccountId, testAccountId), {
93
+ successStates: ['SUCCESS'],
94
+ errorStates: [],
95
+ }, 5000 // 5 seconds
96
+ );
97
+ SpinniesManager_1.default.succeed('createTestAccount', {
98
+ text: en_1.commands.testAccount.create.polling.success(testAccountConfig.accountName, testAccountId),
99
+ });
100
+ }
101
+ catch (err) {
102
+ (0, errorHandlers_1.debugError)(err);
103
+ SpinniesManager_1.default.fail('createTestAccount', {
104
+ text: en_1.commands.testAccount.create.polling.failure,
105
+ });
106
+ }
78
107
  if (formatOutputAsJson) {
79
108
  logger_1.uiLogger.json(jsonOutput);
80
109
  }
package/lang/en.d.ts CHANGED
@@ -189,8 +189,11 @@ Global configuration replaces hubspot.config.yml, and you will be prompted to mi
189
189
  };
190
190
  };
191
191
  readonly auth: {
192
- readonly describe: (configName: string) => string;
192
+ readonly describe: "Configure authentication for your HubSpot account.";
193
+ readonly verboseDescribe: (configName: string, authMethod: string) => string;
193
194
  readonly errors: {
195
+ readonly invalidAccountIdProvided: "--account must be a number.";
196
+ readonly globalConfigFileExists: (accountAuthCommand: string) => string;
194
197
  readonly noConfigFileFound: "No config file was found. To create a new config file, use the \"hs init\" command.";
195
198
  readonly unsupportedAuthType: (type: string, supportedProtocols: string) => string;
196
199
  };
@@ -735,7 +738,8 @@ Global configuration replaces hubspot.config.yml, and you will be prompted to mi
735
738
  };
736
739
  };
737
740
  readonly init: {
738
- readonly describe: (configName: string) => string;
741
+ readonly describe: "Create a CLI config file and configure authentication for your HubSpot account.";
742
+ readonly verboseDescribe: (configName: string, command: string, authMethod: string) => string;
739
743
  readonly options: {
740
744
  readonly authType: {
741
745
  readonly describe: "Authentication mechanism";
@@ -750,14 +754,16 @@ Global configuration replaces hubspot.config.yml, and you will be prompted to mi
750
754
  };
751
755
  readonly success: {
752
756
  readonly configFileCreated: (configPath: string) => string;
753
- readonly configFileUpdated: (account: string, authType: string) => string;
757
+ readonly configFileUpdated: (authType: string, account: string | number) => string;
754
758
  };
755
759
  readonly logs: {
756
760
  readonly updateConfig: "To update an existing config file, use the \"hs auth\" command.";
757
761
  };
758
762
  readonly errors: {
763
+ readonly invalidAccountIdProvided: "--account must be a number.";
759
764
  readonly configFileExists: (configPath: string) => string;
760
765
  readonly bothConfigFilesNotAllowed: (path: string) => string;
766
+ readonly globalConfigFileExists: `You are using our new global configuration for account management, which is not compatible with this command. Please use ${string} instead.`;
761
767
  };
762
768
  };
763
769
  readonly lint: {
@@ -1492,6 +1498,21 @@ ${string}`;
1492
1498
  readonly app: {
1493
1499
  readonly describe: "Commands for managing apps.";
1494
1500
  readonly subcommands: {
1501
+ readonly install: {
1502
+ readonly describe: "Install an app.";
1503
+ readonly options: {
1504
+ readonly appUid: "The uid of the app to install";
1505
+ readonly projectName: "The name of the project to install the app to";
1506
+ readonly testAccountId: "The id of the test account to install the app into";
1507
+ };
1508
+ readonly polling: {
1509
+ readonly start: "Installing app...";
1510
+ readonly success: "App installed successfully";
1511
+ readonly failure: "App installation failed";
1512
+ readonly error: "Error installing app";
1513
+ };
1514
+ readonly example: "Install the app with uid 1234567890 from the project named \"my-project\" into the target account";
1515
+ };
1495
1516
  readonly secret: {
1496
1517
  readonly describe: "Commands for managing secrets.";
1497
1518
  readonly subcommands: {
@@ -1796,10 +1817,12 @@ ${string}`;
1796
1817
  readonly errors: {
1797
1818
  readonly configFileNotFound: (configPath: string) => string;
1798
1819
  readonly configFileParseFailed: (configPath: string) => string;
1799
- readonly failedToCreate: "Failed to create test account";
1800
1820
  };
1801
- readonly success: {
1802
- readonly configFileUpdated: (testAccountName: string, testAccountId: number) => string;
1821
+ readonly polling: {
1822
+ readonly start: (testAccountName: string) => string;
1823
+ readonly syncing: "Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)";
1824
+ readonly success: (testAccountName: string, testAccountId: number) => string;
1825
+ readonly failure: "Failed to sync data into test account. The account may not be ready to use.";
1803
1826
  };
1804
1827
  readonly options: {
1805
1828
  readonly configPath: "The path to the test account config";
@@ -2426,6 +2449,12 @@ ${string}`;
2426
2449
  };
2427
2450
  };
2428
2451
  export declare const lib: {
2452
+ readonly parsing: {
2453
+ readonly unableToParseStringToNumber: "Unable to parse string to number";
2454
+ };
2455
+ readonly configMiddleWare: {
2456
+ readonly invalidAccountIdEnvironmentVariable: "Unable to parse `HUBSPOT_ACCOUNT_ID` environment variable into a number";
2457
+ };
2429
2458
  readonly process: {
2430
2459
  readonly exitDebug: (signal: string) => string;
2431
2460
  };
@@ -2595,6 +2624,9 @@ Run ${string} to upgrade to version ${string}`;
2595
2624
  readonly invalidAuthDistCombo: (authType: string, distribution: string) => string;
2596
2625
  };
2597
2626
  };
2627
+ readonly add: {
2628
+ readonly nothingAdded: "No features added.";
2629
+ };
2598
2630
  readonly validateProjectConfig: {
2599
2631
  readonly configNotFound: `Unable to locate a project configuration file. Try running again from a project directory, or run ${string} to create a new project.`;
2600
2632
  readonly configMissingFields: "The project configuration file is missing required fields.";
@@ -2905,16 +2937,20 @@ Run ${string} to upgrade to version ${string}`;
2905
2937
  readonly languageRequired: "Please select API sample app's language";
2906
2938
  };
2907
2939
  };
2908
- readonly createProjectPrompt: {
2940
+ readonly projectNameAndDestPrompt: {
2909
2941
  readonly enterName: "[--name] Give your project a name: ";
2910
2942
  readonly enterDest: "[--dest] Enter the folder to create the project in:";
2911
- readonly selectTemplate: "[--template] Choose a project template: ";
2912
- readonly features: "[--features] Which features would you like your app to include?";
2913
2943
  readonly errors: {
2914
2944
  readonly nameRequired: "A project name is required";
2915
2945
  readonly destRequired: "A project dest is required";
2916
2946
  readonly invalidDest: "There is an existing project at this destination. Please provide a new path for this project.";
2917
2947
  readonly invalidCharacters: "The selected destination contains invalid characters. Please provide a new path and try again.";
2948
+ };
2949
+ };
2950
+ readonly selectProjectTemplatePrompt: {
2951
+ readonly selectTemplate: "[--template] Choose a project template: ";
2952
+ readonly features: "[--features] Which features would you like your app to include?";
2953
+ readonly errors: {
2918
2954
  readonly invalidTemplate: (template: string) => string;
2919
2955
  readonly projectTemplateRequired: "Project template is required when projectTemplates is provided";
2920
2956
  };
@@ -3019,6 +3055,9 @@ Run ${string} to upgrade to version ${string}`;
3019
3055
  };
3020
3056
  };
3021
3057
  };
3058
+ readonly polling: {
3059
+ readonly timeoutError: (timeoutMs: number) => string;
3060
+ };
3022
3061
  readonly convertFields: {
3023
3062
  readonly positionals: {
3024
3063
  readonly src: {
package/lang/en.js CHANGED
@@ -196,8 +196,11 @@ exports.commands = {
196
196
  },
197
197
  },
198
198
  auth: {
199
- describe: (configName) => `Configure authentication for your HubSpot account. This will update the ${configName} file that stores your account information.`,
199
+ describe: 'Configure authentication for your HubSpot account.',
200
+ verboseDescribe: (configName, authMethod) => `Configure authentication for a HubSpot account. This will update the ${configName} file that stores your account information.\n\nThe recommended authentication method is ${chalk_1.default.bold(authMethod)}, which uses an access token tied to a specific user account.`,
200
201
  errors: {
202
+ invalidAccountIdProvided: `--account must be a number.`,
203
+ globalConfigFileExists: (accountAuthCommand) => `You are using our new global configuration for account management, which is not compatible with this command. Please use ${(0, ui_1.uiCommandReference)(accountAuthCommand)} instead.`,
201
204
  noConfigFileFound: 'No config file was found. To create a new config file, use the "hs init" command.',
202
205
  unsupportedAuthType: (type, supportedProtocols) => `Unsupported auth type: ${type}. The only supported authentication protocols are ${supportedProtocols}.`,
203
206
  },
@@ -744,7 +747,8 @@ exports.commands = {
744
747
  },
745
748
  },
746
749
  init: {
747
- describe: (configName) => `Configure authentication for your HubSpot account. This will create a ${configName} file to store your account information.`,
750
+ describe: 'Create a CLI config file and configure authentication for your HubSpot account.',
751
+ verboseDescribe: (configName, command, authMethod) => `Configure authentication for a HubSpot account. This will create a ${configName} file to store your account information. To configure authentication for additional accounts, run ${command}.\n\nThe recommended authentication method is ${chalk_1.default.bold(authMethod)}, which uses an access token tied to a specific user account.`,
748
752
  options: {
749
753
  authType: {
750
754
  describe: 'Authentication mechanism',
@@ -759,14 +763,16 @@ exports.commands = {
759
763
  },
760
764
  success: {
761
765
  configFileCreated: (configPath) => `Created config file "${configPath}"`,
762
- configFileUpdated: (account, authType) => `Connected account "${account}" using "${authType}" and set it as the default account`,
766
+ configFileUpdated: (authType, account) => `Connected account "${account}" using "${authType}" and set it as the default account`,
763
767
  },
764
768
  logs: {
765
769
  updateConfig: 'To update an existing config file, use the "hs auth" command.',
766
770
  },
767
771
  errors: {
772
+ invalidAccountIdProvided: `--account must be a number.`,
768
773
  configFileExists: (configPath) => `The config file ${configPath} already exists.`,
769
774
  bothConfigFilesNotAllowed: (path) => `Unable to create config file, because there is an existing one at "${path}". To create a new config file, delete the existing one and try again.`,
775
+ globalConfigFileExists: `You are using our new global configuration for account management, which is not compatible with this command. Please use ${(0, ui_1.uiCommandReference)('hs account auth')} instead.`,
770
776
  },
771
777
  },
772
778
  lint: {
@@ -1490,6 +1496,21 @@ exports.commands = {
1490
1496
  app: {
1491
1497
  describe: 'Commands for managing apps.',
1492
1498
  subcommands: {
1499
+ install: {
1500
+ describe: 'Install an app.',
1501
+ options: {
1502
+ appUid: 'The uid of the app to install',
1503
+ projectName: 'The name of the project to install the app to',
1504
+ testAccountId: 'The id of the test account to install the app into',
1505
+ },
1506
+ polling: {
1507
+ start: 'Installing app...',
1508
+ success: 'App installed successfully',
1509
+ failure: 'App installation failed',
1510
+ error: 'Error installing app',
1511
+ },
1512
+ example: 'Install the app with uid 1234567890 from the project named "my-project" into the target account',
1513
+ },
1493
1514
  secret: {
1494
1515
  describe: 'Commands for managing secrets.',
1495
1516
  subcommands: {
@@ -1794,10 +1815,12 @@ exports.commands = {
1794
1815
  errors: {
1795
1816
  configFileNotFound: (configPath) => `No test account config file exists at ${configPath}. Create a test account config file with the ${(0, ui_1.uiCommandReference)('hs test-account create-config')} command.`,
1796
1817
  configFileParseFailed: (configPath) => `Failed to parse test account config file at ${configPath}`,
1797
- failedToCreate: 'Failed to create test account',
1798
1818
  },
1799
- success: {
1800
- configFileUpdated: (testAccountName, testAccountId) => `Test account "${testAccountName}" successfully created with id ${testAccountId}`,
1819
+ polling: {
1820
+ start: (testAccountName) => `Creating test account "${chalk_1.default.bold(testAccountName)}"...`,
1821
+ syncing: 'Test account created! Syncing account data... (may take a few minutes - you can exit and the sync will continue)',
1822
+ success: (testAccountName, testAccountId) => `Test account "${chalk_1.default.bold(testAccountName)}" successfully created with id: ${chalk_1.default.bold(testAccountId)}`,
1823
+ failure: 'Failed to sync data into test account. The account may not be ready to use.',
1801
1824
  },
1802
1825
  options: {
1803
1826
  configPath: 'The path to the test account config',
@@ -2424,6 +2447,12 @@ exports.commands = {
2424
2447
  },
2425
2448
  };
2426
2449
  exports.lib = {
2450
+ parsing: {
2451
+ unableToParseStringToNumber: 'Unable to parse string to number',
2452
+ },
2453
+ configMiddleWare: {
2454
+ invalidAccountIdEnvironmentVariable: 'Unable to parse `HUBSPOT_ACCOUNT_ID` environment variable into a number',
2455
+ },
2427
2456
  process: {
2428
2457
  exitDebug: (signal) => `Attempting to gracefully exit. Triggered by ${signal}`,
2429
2458
  },
@@ -2592,6 +2621,9 @@ exports.lib = {
2592
2621
  invalidAuthDistCombo: (authType, distribution) => `Invalid distribution and auth combination. Apps with distribution '${distribution}' must have auth '${authType}'`,
2593
2622
  },
2594
2623
  },
2624
+ add: {
2625
+ nothingAdded: 'No features added.',
2626
+ },
2595
2627
  validateProjectConfig: {
2596
2628
  configNotFound: `Unable to locate a project configuration file. Try running again from a project directory, or run ${(0, ui_1.uiCommandReference)('hs project create')} to create a new project.`,
2597
2629
  configMissingFields: 'The project configuration file is missing required fields.',
@@ -2900,16 +2932,20 @@ exports.lib = {
2900
2932
  languageRequired: "Please select API sample app's language",
2901
2933
  },
2902
2934
  },
2903
- createProjectPrompt: {
2935
+ projectNameAndDestPrompt: {
2904
2936
  enterName: '[--name] Give your project a name: ',
2905
2937
  enterDest: '[--dest] Enter the folder to create the project in:',
2906
- selectTemplate: '[--template] Choose a project template: ',
2907
- features: '[--features] Which features would you like your app to include?',
2908
2938
  errors: {
2909
2939
  nameRequired: 'A project name is required',
2910
2940
  destRequired: 'A project dest is required',
2911
2941
  invalidDest: 'There is an existing project at this destination. Please provide a new path for this project.',
2912
2942
  invalidCharacters: 'The selected destination contains invalid characters. Please provide a new path and try again.',
2943
+ },
2944
+ },
2945
+ selectProjectTemplatePrompt: {
2946
+ selectTemplate: '[--template] Choose a project template: ',
2947
+ features: '[--features] Which features would you like your app to include?',
2948
+ errors: {
2913
2949
  invalidTemplate: (template) => `[--template] Could not find template "${template}". Please choose an available template:`,
2914
2950
  projectTemplateRequired: 'Project template is required when projectTemplates is provided',
2915
2951
  },
@@ -3014,6 +3050,9 @@ exports.lib = {
3014
3050
  },
3015
3051
  },
3016
3052
  },
3053
+ polling: {
3054
+ timeoutError: (timeoutMs) => `Polling timed out after ${timeoutMs}ms.`,
3055
+ },
3017
3056
  convertFields: {
3018
3057
  positionals: {
3019
3058
  src: {
@@ -18,7 +18,7 @@ const ui_1 = require("../ui");
18
18
  const lang_1 = require("../lang");
19
19
  const accountTypes_1 = require("../accountTypes");
20
20
  const selectPublicAppForMigrationPrompt_1 = require("../prompts/selectPublicAppForMigrationPrompt");
21
- const createProjectPrompt_1 = require("../prompts/createProjectPrompt");
21
+ const projectNameAndDestPrompt_1 = require("../prompts/projectNameAndDestPrompt");
22
22
  const ensureProjectExists_1 = require("../projects/ensureProjectExists");
23
23
  const usageTracking_1 = require("../usageTracking");
24
24
  const SpinniesManager_1 = __importDefault(require("../ui/SpinniesManager"));
@@ -58,8 +58,7 @@ async function migrateApp2023_2(derivedAccountId, options, accountConfig) {
58
58
  (0, errorHandlers_1.logError)(error, new errorHandlers_1.ApiErrorContext({ accountId: derivedAccountId }));
59
59
  return process.exit(exitCodes_1.EXIT_CODES.ERROR);
60
60
  }
61
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(options);
62
- const { name: projectName, dest: projectDest } = createProjectPromptResponse;
61
+ const { name: projectName, dest: projectDest } = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(options);
63
62
  const { projectExists } = await (0, ensureProjectExists_1.ensureProjectExists)(derivedAccountId, projectName, {
64
63
  allowCreate: false,
65
64
  noLogs: true,
@@ -109,7 +109,7 @@ describe('lib/middleware/configMiddleware', () => {
109
109
  $0: 'hs',
110
110
  };
111
111
  await (0, configMiddleware_1.injectAccountIdMiddleware)(argv);
112
- expect(argv.providedAccountId).toBeUndefined();
112
+ expect(argv.userProvidedAccount).toBeUndefined();
113
113
  expect(argv.derivedAccountId).toBe(123);
114
114
  expect(getAccountIdSpy).not.toHaveBeenCalled();
115
115
  process.env = originalEnv;
@@ -123,7 +123,7 @@ describe('lib/middleware/configMiddleware', () => {
123
123
  $0: 'hs',
124
124
  };
125
125
  await (0, configMiddleware_1.injectAccountIdMiddleware)(argv);
126
- expect(argv.providedAccountId).toBe('test-account');
126
+ expect(argv.userProvidedAccount).toBe('test-account');
127
127
  expect(argv.derivedAccountId).toBe(456);
128
128
  expect(getAccountIdSpy).toHaveBeenCalledWith('test-account');
129
129
  });
@@ -11,6 +11,9 @@ const exitCodes_1 = require("../enums/exitCodes");
11
11
  const lang_1 = require("../lang");
12
12
  const ui_1 = require("../ui");
13
13
  const utils_1 = require("./utils");
14
+ const parsing_1 = require("../parsing");
15
+ const logger_2 = require("../ui/logger");
16
+ const en_1 = require("../../lang/en");
14
17
  function handleDeprecatedEnvVariables(argv) {
15
18
  // HUBSPOT_PORTAL_ID is deprecated, but we'll still support it for now
16
19
  // The HubSpot GH Deploy Action still uses HUBSPOT_PORTAL_ID
@@ -29,9 +32,14 @@ function handleDeprecatedEnvVariables(argv) {
29
32
  async function injectAccountIdMiddleware(argv) {
30
33
  const { account } = argv;
31
34
  // Preserves the original --account flag for certain commands.
32
- argv.providedAccountId = account;
35
+ argv.userProvidedAccount = account;
33
36
  if (argv.useEnv && process.env.HUBSPOT_ACCOUNT_ID) {
34
- argv.derivedAccountId = parseInt(process.env.HUBSPOT_ACCOUNT_ID, 10);
37
+ try {
38
+ argv.derivedAccountId = (0, parsing_1.parseStringToNumber)(process.env.HUBSPOT_ACCOUNT_ID);
39
+ }
40
+ catch (err) {
41
+ logger_2.uiLogger.error(en_1.lib.configMiddleWare.invalidAccountIdEnvironmentVariable);
42
+ }
35
43
  }
36
44
  else {
37
45
  argv.derivedAccountId = (0, config_1.getAccountId)(account);
@@ -0,0 +1 @@
1
+ export declare function parseStringToNumber(maybeNumber: string): number;
package/lib/parsing.js ADDED
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseStringToNumber = parseStringToNumber;
4
+ const en_1 = require("../lang/en");
5
+ function parseStringToNumber(maybeNumber) {
6
+ const result = parseInt(maybeNumber, 10);
7
+ if (Number.isNaN(result) || !/^-?\d+$/.test(maybeNumber)) {
8
+ throw new Error(en_1.lib.parsing.unableToParseStringToNumber);
9
+ }
10
+ return result;
11
+ }
package/lib/polling.d.ts CHANGED
@@ -17,5 +17,5 @@ type PollingCallback<T extends GenericPollingResponse> = () => HubSpotPromise<T>
17
17
  export declare function poll<T extends GenericPollingResponse>(callback: PollingCallback<T>, statusLookup?: {
18
18
  successStates: string[];
19
19
  errorStates: string[];
20
- }): Promise<T>;
20
+ }, timeoutMs?: number): Promise<T>;
21
21
  export {};
package/lib/polling.js CHANGED
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DEFAULT_POLLING_STATUS_LOOKUP = exports.DEFAULT_POLLING_STATES = void 0;
4
4
  exports.poll = poll;
5
5
  const constants_1 = require("./constants");
6
+ const en_1 = require("../lang/en");
6
7
  exports.DEFAULT_POLLING_STATES = {
7
8
  STARTED: 'STARTED',
8
9
  SUCCESS: 'SUCCESS',
@@ -18,7 +19,8 @@ exports.DEFAULT_POLLING_STATUS_LOOKUP = {
18
19
  exports.DEFAULT_POLLING_STATES.FAILURE,
19
20
  ],
20
21
  };
21
- function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP) {
22
+ function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP, timeoutMs = 60000 // Default 60 second timeout
23
+ ) {
22
24
  return new Promise((resolve, reject) => {
23
25
  const pollInterval = setInterval(async () => {
24
26
  try {
@@ -26,17 +28,25 @@ function poll(callback, statusLookup = exports.DEFAULT_POLLING_STATUS_LOOKUP) {
26
28
  const { status } = pollResp;
27
29
  if (statusLookup.successStates.includes(status)) {
28
30
  clearInterval(pollInterval);
31
+ clearTimeout(timeoutId);
29
32
  resolve(pollResp);
30
33
  }
31
34
  else if (statusLookup.errorStates.includes(status)) {
32
35
  clearInterval(pollInterval);
36
+ clearTimeout(timeoutId);
33
37
  reject(pollResp);
34
38
  }
35
39
  }
36
40
  catch (error) {
37
41
  clearInterval(pollInterval);
42
+ clearTimeout(timeoutId);
38
43
  reject(error);
39
44
  }
40
45
  }, constants_1.DEFAULT_POLLING_DELAY);
46
+ // Set a timeout to stop polling after specified duration
47
+ const timeoutId = setTimeout(() => {
48
+ clearInterval(pollInterval);
49
+ reject(new Error(en_1.lib.polling.timeoutError(timeoutMs)));
50
+ }, timeoutMs);
41
51
  });
42
52
  }
@@ -66,6 +66,10 @@ async function v3AddComponent(args, projectDir, projectConfig) {
66
66
  components.push(path_1.default.join(projectConfig.platformVersion, parentComponent.path));
67
67
  }
68
68
  }
69
+ if (components.length === 0) {
70
+ logger_1.uiLogger.log(en_1.lib.projects.add.nothingAdded);
71
+ return;
72
+ }
69
73
  await (0, github_1.cloneGithubRepo)(constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH, projectDir, {
70
74
  sourceDir: components,
71
75
  hideLogs: true,
@@ -1,6 +1,6 @@
1
1
  import { ArgumentsCamelCase } from 'yargs';
2
2
  import { ProjectTemplateRepoConfig } from '../../../types/Projects';
3
- import { CreateProjectPromptResponse } from '../../prompts/createProjectPrompt';
3
+ import { SelectProjectTemplatePromptResponse, ProjectNameAndDestPromptResponse } from '../../prompts/selectProjectTemplatePrompt';
4
4
  import { AccountArgs, CommonArgs, ConfigArgs, EnvironmentArgs } from '../../../types/Yargs';
5
5
  import { RepoPath } from '@hubspot/local-dev-lib/types/Github';
6
6
  export type ProjectCreateArgs = CommonArgs & ConfigArgs & AccountArgs & EnvironmentArgs & {
@@ -19,5 +19,6 @@ export declare function handleProjectCreationFlow(args: ArgumentsCamelCase<Proje
19
19
  distribution?: string;
20
20
  repoConfig?: ProjectTemplateRepoConfig;
21
21
  projectContents?: string;
22
- createProjectPromptResponse: CreateProjectPromptResponse;
22
+ selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
23
+ projectNameAndDestPromptResponse: ProjectNameAndDestPromptResponse;
23
24
  }>;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleProjectCreationFlow = handleProjectCreationFlow;
4
- const createProjectPrompt_1 = require("../../prompts/createProjectPrompt");
4
+ const selectProjectTemplatePrompt_1 = require("../../prompts/selectProjectTemplatePrompt");
5
+ const projectNameAndDestPrompt_1 = require("../../prompts/projectNameAndDestPrompt");
5
6
  const constants_1 = require("../../constants");
6
7
  const buildAndDeploy_1 = require("../buildAndDeploy");
7
8
  const v3_1 = require("./v3");
@@ -12,15 +13,17 @@ const exitCodes_1 = require("../../enums/exitCodes");
12
13
  async function handleProjectCreationFlow(args) {
13
14
  const { platformVersion, templateSource, projectBase, auth: providedAuth, distribution: providedDistribution, } = args;
14
15
  const repo = templateSource || constants_1.HUBSPOT_PROJECT_COMPONENTS_GITHUB_PATH;
16
+ const projectNameAndDestPromptResponse = await (0, projectNameAndDestPrompt_1.projectNameAndDestPrompt)(args);
15
17
  if ((0, buildAndDeploy_1.useV3Api)(platformVersion)) {
16
18
  const { componentTemplateChoices, authType, distribution, repoConfig, projectContents, } = await (0, v3_1.v3ComponentFlow)(platformVersion, projectBase, providedAuth, providedDistribution);
17
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(args, undefined, projectContents !== v3_1.EMPTY_PROJECT ? componentTemplateChoices : undefined);
19
+ const selectProjectTemplatePromptResponse = await (0, selectProjectTemplatePrompt_1.selectProjectTemplatePrompt)(args, undefined, projectContents !== v3_1.EMPTY_PROJECT ? componentTemplateChoices : undefined);
18
20
  return {
19
21
  authType,
20
22
  distribution,
21
23
  repoConfig,
22
24
  projectContents,
23
- createProjectPromptResponse,
25
+ selectProjectTemplatePromptResponse,
26
+ projectNameAndDestPromptResponse,
24
27
  };
25
28
  }
26
29
  const projectTemplates = await (0, legacy_1.getProjectTemplateListFromRepo)(repo, 'main');
@@ -28,6 +31,9 @@ async function handleProjectCreationFlow(args) {
28
31
  logger_1.uiLogger.error(en_1.commands.project.create.errors.failedToFetchProjectList);
29
32
  process.exit(exitCodes_1.EXIT_CODES.ERROR);
30
33
  }
31
- const createProjectPromptResponse = await (0, createProjectPrompt_1.createProjectPrompt)(args, projectTemplates);
32
- return { createProjectPromptResponse };
34
+ const selectProjectTemplatePromptResponse = await (0, selectProjectTemplatePrompt_1.selectProjectTemplatePrompt)(args, projectTemplates);
35
+ return {
36
+ selectProjectTemplatePromptResponse,
37
+ projectNameAndDestPromptResponse,
38
+ };
33
39
  }
@@ -1,6 +1,6 @@
1
1
  import { ComponentTemplate, ComponentTemplateChoice, ProjectTemplateRepoConfig } from '../../../types/Projects';
2
2
  import { ProjectMetadata } from '@hubspot/project-parsing-lib/src/lib/project';
3
- import { CreateProjectPromptResponse } from '../../prompts/createProjectPrompt';
3
+ import { SelectProjectTemplatePromptResponse } from '../../prompts/selectProjectTemplatePrompt';
4
4
  export declare const EMPTY_PROJECT = "empty";
5
5
  export declare const PROJECT_WITH_APP = "app";
6
6
  export declare function createV3App(providedAuth: string | undefined, providedDistribution: string | undefined): Promise<{
@@ -16,8 +16,8 @@ type V3ComponentInfo = {
16
16
  componentTemplateChoices?: ComponentTemplateChoice[];
17
17
  };
18
18
  export declare function v3ComponentFlow(platformVersion: string, projectBase: string | undefined, providedAuth: string | undefined, providedDistribution: string | undefined): Promise<V3ComponentInfo>;
19
- export declare function generateComponentPaths({ createProjectPromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
20
- createProjectPromptResponse: CreateProjectPromptResponse;
19
+ export declare function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }: {
20
+ selectProjectTemplatePromptResponse: SelectProjectTemplatePromptResponse;
21
21
  platformVersion: string;
22
22
  repoConfig?: ProjectTemplateRepoConfig;
23
23
  projectContents?: string;
@@ -134,11 +134,11 @@ async function v3ComponentFlow(platformVersion, projectBase, providedAuth, provi
134
134
  repoConfig,
135
135
  };
136
136
  }
137
- function generateComponentPaths({ createProjectPromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
137
+ function generateComponentPaths({ selectProjectTemplatePromptResponse, platformVersion, repoConfig, projectContents, authType, distribution, }) {
138
138
  if (!(0, buildAndDeploy_1.useV3Api)(platformVersion)) {
139
139
  return [];
140
140
  }
141
- const components = createProjectPromptResponse.componentTemplates?.map((componentTemplate) => {
141
+ const components = selectProjectTemplatePromptResponse.componentTemplates?.map((componentTemplate) => {
142
142
  return path_1.default.join(platformVersion, componentTemplate.path);
143
143
  }) || [];
144
144
  if (projectContents && projectContents !== exports.EMPTY_PROJECT) {
@@ -16,15 +16,16 @@ declare class LocalDevProcess {
16
16
  [key: string]: IntermediateRepresentationNodeLocalDev;
17
17
  };
18
18
  get logger(): LocalDevLogger;
19
- get configFilesUpdatedSinceLastUpload(): Set<string>;
20
19
  private setupDevServers;
21
20
  private startDevServers;
22
21
  private cleanupDevServers;
23
22
  private compareLocalProjectToDeployed;
24
23
  private projectConfigValidForUpload;
24
+ private getIntermediateRepresentation;
25
25
  private updateProjectNodes;
26
+ private updateProjectNodesAfterUpload;
26
27
  handleFileChange(filePath: string, event: string): Promise<void>;
27
- handleConfigFileChange(filePath: string, event: string): Promise<void>;
28
+ handleConfigFileChange(): Promise<void>;
28
29
  start(): Promise<void>;
29
30
  stop(showProgress?: boolean): Promise<void>;
30
31
  uploadProject(): Promise<boolean>;