@hubspot/cli 8.13.0 → 8.14.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,25 @@
1
1
  import { uiLogger } from '../../../lib/ui/logger.js';
2
- // This package is not typed, so we need to use require
3
- import { start as startTestServer } from '@hubspot/serverless-dev-runtime';
4
2
  import { commands } from '../../../lang/en.js';
3
+ import { EXIT_CODES } from '../../../lib/enums/exitCodes.js';
4
+ import { startServerlessDevRuntime } from '../../../lib/cms/serverlessDevRuntime.js';
5
+ import { logError } from '../../../lib/errorHandlers/index.js';
5
6
  import { makeWrappedYargsHandler } from '../../../lib/yargs/makeWrappedYargsHandler.js';
6
7
  import { makeYargsBuilder } from '../../../lib/yargsUtils.js';
7
8
  const command = 'server <path>';
8
9
  const describe = undefined;
9
10
  async function handler(args) {
10
- const { path: functionPath, derivedAccountId } = args;
11
+ const { path: functionPath, derivedAccountId, exit } = args;
11
12
  uiLogger.debug(commands.cms.subcommands.function.subcommands.server.debug.startingServer(functionPath));
12
- startTestServer({
13
- accountId: derivedAccountId,
14
- ...args,
15
- });
13
+ try {
14
+ await startServerlessDevRuntime({
15
+ accountId: derivedAccountId,
16
+ ...args,
17
+ });
18
+ }
19
+ catch (e) {
20
+ logError(e);
21
+ return exit(EXIT_CODES.ERROR);
22
+ }
16
23
  }
17
24
  function functionServerBuilder(yargs) {
18
25
  yargs.positional('path', {
@@ -17,6 +17,7 @@ import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler
17
17
  import { UploadSchema, } from '../../lib/jsonOutput.js';
18
18
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
19
19
  import { projectProfilePrompt } from '../../lib/prompts/projectProfilePrompt.js';
20
+ import { uiDeprecatedTag } from '../../lib/ui/index.js';
20
21
  import { showMcpPromotionNudge } from '../../lib/mcp/promotion.js';
21
22
  import { PLATFORM_VERSIONS } from '@hubspot/project-parsing-lib/constants';
22
23
  const command = 'upload';
@@ -37,6 +38,9 @@ async function handlePreview(accountId, projectId, buildId, targetPortalId) {
37
38
  }
38
39
  async function handler(args) {
39
40
  const { force = false, forceCreate = false, message, derivedAccountId, skipValidation, skipNpmAudit, skipAutoDeploy, formatOutputAsJson, profile: profileOption, useEnv: useEnvOption, preview, target: targetPortalId, exit, addUsageMetadata, addJsonOutput, } = args;
41
+ if (forceCreate) {
42
+ uiDeprecatedTag(commands.project.upload.logs.forceCreateDeprecated);
43
+ }
40
44
  const { projectConfig, projectDir } = await getProjectConfig();
41
45
  try {
42
46
  validateProjectConfig(projectConfig, projectDir);
@@ -14,9 +14,9 @@ import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
14
14
  import { handleKeypress, handleExit } from '../../lib/process.js';
15
15
  import { makeWrappedYargsHandler } from '../../lib/yargs/makeWrappedYargsHandler.js';
16
16
  import { makeYargsBuilder } from '../../lib/yargsUtils.js';
17
- import { uiDeprecatedTag } from '../../lib/ui/index.js';
17
+ import { uiCommandRelocatedMessage, uiCommandRenamedDescription, } from '../../lib/ui/index.js';
18
18
  const command = 'watch';
19
- const describe = uiDeprecatedTag(commands.project.watch.describe, false);
19
+ const describe = uiCommandRenamedDescription(commands.project.watch.describe, 'hs project dev');
20
20
  async function handleBuildStatus(accountId, projectName, buildId) {
21
21
  const { isAutoDeployEnabled, deployStatusTaskLocator } = await pollBuildStatus(accountId, projectName, buildId, null);
22
22
  if (isAutoDeployEnabled && deployStatusTaskLocator) {
@@ -57,6 +57,7 @@ function handleUserInput(accountId, projectName, currentBuildId, exit) {
57
57
  }
58
58
  async function handler(args) {
59
59
  const { initialUpload, derivedAccountId, exit } = args;
60
+ uiCommandRelocatedMessage('hs project dev');
60
61
  const { projectConfig, projectDir } = await getProjectConfig();
61
62
  if (!projectConfig || !projectDir) {
62
63
  uiLogger.error(commands.project.watch.errors.projectConfigNotFound);
package/lang/en.d.ts CHANGED
@@ -1901,6 +1901,7 @@ export declare const commands: {
1901
1901
  withPreview: string;
1902
1902
  };
1903
1903
  logs: {
1904
+ forceCreateDeprecated: string;
1904
1905
  buildSucceeded: (buildId: number) => string;
1905
1906
  readyToGoLive: string;
1906
1907
  runCommand: (command: string) => string;
@@ -4494,6 +4495,13 @@ export declare const lib: {
4494
4495
  copyingProjectFilesFailed: string;
4495
4496
  };
4496
4497
  };
4498
+ cms: {
4499
+ serverlessDevRuntime: {
4500
+ installStarted: (targetVersion: string) => string;
4501
+ installSucceeded: string;
4502
+ installFailed: string;
4503
+ };
4504
+ };
4497
4505
  theme: {
4498
4506
  cmsDevServerProcess: {
4499
4507
  installStarted: (targetVersion: string) => string;
package/lang/en.js CHANGED
@@ -1917,6 +1917,7 @@ export const commands = {
1917
1917
  withPreview: 'Upload and preview the build on a target portal',
1918
1918
  },
1919
1919
  logs: {
1920
+ forceCreateDeprecated: `The ${uiCommandReference('--force-create')} flag is deprecated. Use ${uiCommandReference('--force')} instead.`,
1920
1921
  buildSucceeded: (buildId) => `Build #${buildId} succeeded\n`,
1921
1922
  readyToGoLive: '🚀 Ready to take your project live?',
1922
1923
  runCommand: (command) => `Run \`${uiCommandReference(command)}\``,
@@ -4531,6 +4532,13 @@ export const lib = {
4531
4532
  copyingProjectFilesFailed: 'Unable to copy migrated project files',
4532
4533
  },
4533
4534
  },
4535
+ cms: {
4536
+ serverlessDevRuntime: {
4537
+ installStarted: (targetVersion) => `Installing serverless-dev-runtime ${targetVersion}...`,
4538
+ installSucceeded: 'serverless-dev-runtime setup complete',
4539
+ installFailed: 'Failed to install serverless-dev-runtime',
4540
+ },
4541
+ },
4534
4542
  theme: {
4535
4543
  cmsDevServerProcess: {
4536
4544
  installStarted: (targetVersion) => `Installing cms-dev-server ${targetVersion}...`,
@@ -0,0 +1 @@
1
+ export declare function startServerlessDevRuntime(options: any): Promise<void>;
@@ -0,0 +1,72 @@
1
+ import { spawn } from 'child_process';
2
+ import { createRequire } from 'module';
3
+ import path from 'path';
4
+ import fs from 'fs';
5
+ import os from 'os';
6
+ import SpinniesManager from '../ui/SpinniesManager.js';
7
+ import { lib } from '../../lang/en.js';
8
+ const TARGET_SERVERLESS_RUNTIME_VERSION = '7.0.7';
9
+ const CACHE_DIR = path.join(os.homedir(), '.hscli', '.serverless-runtime-cache');
10
+ async function ensureServerlessRuntimeInstalled() {
11
+ const packageJsonPath = path.join(CACHE_DIR, 'node_modules', '@hubspot', 'serverless-dev-runtime', 'package.json');
12
+ let needsInstall = true;
13
+ if (fs.existsSync(packageJsonPath)) {
14
+ try {
15
+ const installed = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
16
+ if (installed.version === TARGET_SERVERLESS_RUNTIME_VERSION) {
17
+ needsInstall = false;
18
+ }
19
+ }
20
+ catch {
21
+ needsInstall = true;
22
+ }
23
+ }
24
+ if (!needsInstall) {
25
+ return;
26
+ }
27
+ SpinniesManager.init({ succeedColor: 'white' });
28
+ SpinniesManager.add('serverless-runtime-install', {
29
+ text: lib.cms.serverlessDevRuntime.installStarted(TARGET_SERVERLESS_RUNTIME_VERSION),
30
+ });
31
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
32
+ const nodeModulesDir = path.join(CACHE_DIR, 'node_modules');
33
+ if (fs.existsSync(nodeModulesDir)) {
34
+ fs.rmSync(nodeModulesDir, { recursive: true, force: true });
35
+ }
36
+ await new Promise((resolve, reject) => {
37
+ const installProcess = spawn('npm', [
38
+ 'install',
39
+ `@hubspot/serverless-dev-runtime@${TARGET_SERVERLESS_RUNTIME_VERSION}`,
40
+ '--production',
41
+ '--no-save',
42
+ '--loglevel=error',
43
+ ], { cwd: CACHE_DIR, stdio: 'ignore' });
44
+ installProcess.on('close', code => {
45
+ if (code === 0) {
46
+ SpinniesManager.succeed('serverless-runtime-install', {
47
+ text: lib.cms.serverlessDevRuntime.installSucceeded,
48
+ });
49
+ resolve();
50
+ }
51
+ else {
52
+ SpinniesManager.fail('serverless-runtime-install', {
53
+ text: lib.cms.serverlessDevRuntime.installFailed,
54
+ });
55
+ reject(new Error(lib.cms.serverlessDevRuntime.installFailed));
56
+ }
57
+ });
58
+ installProcess.on('error', error => {
59
+ SpinniesManager.fail('serverless-runtime-install', {
60
+ text: lib.cms.serverlessDevRuntime.installFailed,
61
+ });
62
+ reject(error);
63
+ });
64
+ });
65
+ }
66
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
67
+ export async function startServerlessDevRuntime(options) {
68
+ await ensureServerlessRuntimeInstalled();
69
+ const requireFromCache = createRequire(path.join(CACHE_DIR, 'package.json'));
70
+ const { start } = requireFromCache('@hubspot/serverless-dev-runtime');
71
+ start(options);
72
+ }
@@ -82,6 +82,7 @@ export declare const FEATURES: {
82
82
  readonly APP_EVENTS: "Developers:UnifiedApps:AppEventsAccess";
83
83
  readonly THEME_MIGRATION_2025_2: "Developers:ProjectThemeMigrations:2025.2";
84
84
  readonly AGENT_TOOLS: "ThirdPartyAgentTools";
85
+ readonly APP_ACTIONS: "Developers:AppActions";
85
86
  };
86
87
  export declare const LOCAL_DEV_UI_MESSAGE_SEND_TYPES: {
87
88
  UPLOAD_SUCCESS: string;
package/lib/constants.js CHANGED
@@ -74,6 +74,7 @@ export const FEATURES = {
74
74
  APP_EVENTS: 'Developers:UnifiedApps:AppEventsAccess',
75
75
  THEME_MIGRATION_2025_2: 'Developers:ProjectThemeMigrations:2025.2',
76
76
  AGENT_TOOLS: 'ThirdPartyAgentTools',
77
+ APP_ACTIONS: 'Developers:AppActions',
77
78
  };
78
79
  export const LOCAL_DEV_UI_MESSAGE_SEND_TYPES = {
79
80
  UPLOAD_SUCCESS: 'server:uploadSuccess',
@@ -48,6 +48,7 @@ export async function createV2App(providedAuth, providedDistribution) {
48
48
  const componentTypeToGateMap = {
49
49
  [AppEventsKey]: FEATURES.APP_EVENTS,
50
50
  'workflow-action-tool': FEATURES.AGENT_TOOLS,
51
+ 'crm-bulk-action': FEATURES.APP_ACTIONS,
51
52
  };
52
53
  export async function calculateComponentTemplateChoices(components, authType, distribution, accountId, projectMetadata) {
53
54
  const enabledComponents = [];
@@ -153,14 +153,14 @@ class LocalDevProcess {
153
153
  return this.state.actions.exit(EXIT_CODES.ERROR);
154
154
  }
155
155
  this.logger.startupMessage();
156
- if (isConfigFlagEnabled(CONFIG_FLAGS.AUTO_OPEN_BROWSER, true)) {
157
- this.openLocalDevUi();
158
- }
159
156
  await this.startDevServers();
160
157
  const devSessionRegistered = await this.devSessionManager.registerSession();
161
158
  if (!devSessionRegistered) {
162
159
  return this.state.actions.exit(EXIT_CODES.ERROR);
163
160
  }
161
+ if (isConfigFlagEnabled(CONFIG_FLAGS.AUTO_OPEN_BROWSER, true)) {
162
+ this.openLocalDevUi();
163
+ }
164
164
  this.state.devServersStarted = true;
165
165
  this.logger.monitorConsoleOutput();
166
166
  }
@@ -20,6 +20,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
20
20
  settings: "settings";
21
21
  "app-event": "app-event";
22
22
  "workflow-action-tool": "workflow-action-tool";
23
+ "crm-bulk-action": "crm-bulk-action";
23
24
  page: "page";
24
25
  webhooks: "webhooks";
25
26
  "app-function": "app-function";
@@ -24,6 +24,7 @@ declare const inputSchemaZodObject: z.ZodObject<{
24
24
  settings: "settings";
25
25
  "app-event": "app-event";
26
26
  "workflow-action-tool": "workflow-action-tool";
27
+ "crm-bulk-action": "crm-bulk-action";
27
28
  page: "page";
28
29
  webhooks: "webhooks";
29
30
  "app-function": "app-function";
@@ -6,6 +6,7 @@ export declare const features: z.ZodOptional<z.ZodArray<z.ZodEnum<{
6
6
  settings: "settings";
7
7
  "app-event": "app-event";
8
8
  "workflow-action-tool": "workflow-action-tool";
9
+ "crm-bulk-action": "crm-bulk-action";
9
10
  page: "page";
10
11
  webhooks: "webhooks";
11
12
  "app-function": "app-function";
@@ -18,8 +18,9 @@ export const features = z
18
18
  'app-event',
19
19
  'scim',
20
20
  'page',
21
+ 'crm-bulk-action',
21
22
  ]))
22
- .describe('The features to include in the project, multiple options can be selected. "app-function" is also known as a private serverless function. "app-function-endpoint" is a serverless functions that is publicly accessible via endpoint. "workflow-action" is also known as a custom workflow action. "workflow-action-tool" is also known as agent tools.')
23
+ .describe('The features to include in the project, multiple options can be selected. "app-function" is also known as a private serverless function. "app-function-endpoint" is a serverless functions that is publicly accessible via endpoint. "workflow-action" is also known as a custom workflow action. "workflow-action-tool" is also known as agent tools. "crm-bulk-action" is an app actions extension that lets users act on multiple CRM records at once.')
23
24
  .optional();
24
25
  export const docsSearchQuery = z
25
26
  .string()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/cli",
3
- "version": "8.13.0",
3
+ "version": "8.14.0-beta.0",
4
4
  "description": "The official CLI for developing on HubSpot",
5
5
  "license": "Apache-2.0",
6
6
  "repository": "https://github.com/HubSpot/hubspot-cli",
@@ -10,10 +10,9 @@
10
10
  "!**/__tests__/**"
11
11
  ],
12
12
  "dependencies": {
13
- "@hubspot/local-dev-lib": "5.10.2",
14
- "@hubspot/project-parsing-lib": "0.21.0",
15
- "@hubspot/serverless-dev-runtime": "7.0.7",
16
- "@hubspot/ui-extensions-dev-server": "2.1.0",
13
+ "@hubspot/local-dev-lib": "5.10.3",
14
+ "@hubspot/project-parsing-lib": "0.22.1",
15
+ "@hubspot/ui-extensions-dev-server": "2.1.2",
17
16
  "@inquirer/prompts": "7.1.0",
18
17
  "@modelcontextprotocol/sdk": "1.29.0",
19
18
  "archiver": "7.0.1",
@@ -21,13 +20,13 @@
21
20
  "chokidar": "3.6.0",
22
21
  "cli-cursor": "3.1.0",
23
22
  "cli-progress": "3.12.0",
24
- "express": "4.22.1",
23
+ "express": "4.22.2",
25
24
  "findup-sync": "4.0.0",
26
25
  "fs-extra": "8.1.0",
27
26
  "ink": "6.6.0",
28
27
  "ink-spinner": "5.0.0",
29
28
  "ink-text-input": "6.0.0",
30
- "js-yaml": "4.1.1",
29
+ "js-yaml": "4.3.1",
31
30
  "minimatch": "10.2.5",
32
31
  "moment": "2.30.1",
33
32
  "open": "7.4.2",
@@ -36,9 +35,9 @@
36
35
  "semver": "7.6.3",
37
36
  "strip-ansi": "7.1.0",
38
37
  "table": "6.9.0",
39
- "tmp": "0.2.4",
38
+ "tmp": "0.2.7",
40
39
  "update-notifier": "7.3.1",
41
- "ws": "8.20.0",
40
+ "ws": "8.21.0",
42
41
  "yargs": "17.7.2",
43
42
  "yargs-parser": "21.1.1",
44
43
  "zod": "^4.4.3"
@@ -61,7 +60,7 @@
61
60
  "@typescript-eslint/eslint-plugin": "^8.30.1",
62
61
  "@typescript-eslint/parser": "^8.11.0",
63
62
  "@vitest/coverage-v8": "^2.1.9",
64
- "axios": "1.18.1",
63
+ "axios": "1.19.0",
65
64
  "eslint": "^8.56.0",
66
65
  "eslint-plugin-import": "^2.31.0",
67
66
  "husky": "^4.3.8",
@@ -125,6 +124,8 @@
125
124
  },
126
125
  "resolutions": {
127
126
  "eslint-visitor-keys": "4.2.0",
128
- "@eslint-community/eslint-utils": "4.9.0"
127
+ "@eslint-community/eslint-utils": "4.9.0",
128
+ "@opentelemetry/core": "2.10.0",
129
+ "axios": "1.19.0"
129
130
  }
130
131
  }