@hubspot/cli 8.0.1-experimental.0 → 8.0.3-experimental.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.
Files changed (109) hide show
  1. package/bin/cli.js +8 -5
  2. package/commands/__tests__/getStarted.test.js +12 -0
  3. package/commands/__tests__/project.test.js +30 -0
  4. package/commands/account/auth.js +8 -97
  5. package/commands/account/use.js +19 -4
  6. package/commands/cms/module/marketplace-validate.js +23 -5
  7. package/commands/cms/theme/marketplace-validate.js +25 -6
  8. package/commands/getStarted.d.ts +2 -1
  9. package/commands/getStarted.js +38 -15
  10. package/commands/mcp/__tests__/start.test.js +1 -67
  11. package/commands/mcp/setup.js +1 -2
  12. package/commands/mcp/start.js +1 -19
  13. package/commands/mcp.js +1 -2
  14. package/commands/project.js +22 -1
  15. package/lang/en.d.ts +53 -7
  16. package/lang/en.js +59 -13
  17. package/lib/CLIWebSocketServer.d.ts +28 -0
  18. package/lib/CLIWebSocketServer.js +91 -0
  19. package/lib/__tests__/CLIWebSocketServer.test.d.ts +1 -0
  20. package/lib/__tests__/CLIWebSocketServer.test.js +252 -0
  21. package/lib/__tests__/accountAuth.test.d.ts +1 -0
  22. package/lib/__tests__/accountAuth.test.js +258 -0
  23. package/lib/__tests__/commandSuggestion.test.d.ts +1 -0
  24. package/lib/__tests__/commandSuggestion.test.js +119 -0
  25. package/lib/accountAuth.d.ts +10 -0
  26. package/lib/accountAuth.js +105 -0
  27. package/lib/app/urls.d.ts +1 -0
  28. package/lib/app/urls.js +4 -0
  29. package/lib/commandSuggestion.d.ts +3 -0
  30. package/lib/commandSuggestion.js +45 -0
  31. package/lib/constants.d.ts +0 -1
  32. package/lib/constants.js +0 -1
  33. package/lib/errors/ProjectErrors.d.ts +15 -0
  34. package/lib/errors/ProjectErrors.js +30 -0
  35. package/lib/getStarted/getStartedV2.d.ts +7 -0
  36. package/lib/getStarted/getStartedV2.js +18 -0
  37. package/lib/getStartedV2Actions.d.ts +37 -0
  38. package/lib/getStartedV2Actions.js +146 -0
  39. package/lib/marketplaceValidate.d.ts +1 -1
  40. package/lib/marketplaceValidate.js +23 -41
  41. package/lib/mcp/__tests__/setup.test.js +0 -17
  42. package/lib/mcp/setup.d.ts +0 -1
  43. package/lib/mcp/setup.js +59 -103
  44. package/lib/projects/ProjectLogsManager.d.ts +12 -3
  45. package/lib/projects/ProjectLogsManager.js +70 -12
  46. package/lib/projects/__tests__/LocalDevWebsocketServer.test.js +43 -175
  47. package/lib/projects/__tests__/ProjectLogsManager.test.js +131 -18
  48. package/lib/projects/__tests__/platformVersion.test.js +37 -1
  49. package/lib/projects/__tests__/projects.test.js +6 -2
  50. package/lib/projects/components.d.ts +6 -0
  51. package/lib/projects/components.js +1 -1
  52. package/lib/projects/config.js +9 -2
  53. package/lib/projects/localDev/LocalDevWebsocketServer.d.ts +2 -7
  54. package/lib/projects/localDev/LocalDevWebsocketServer.js +51 -98
  55. package/lib/projects/localDev/helpers/project.d.ts +4 -1
  56. package/lib/projects/localDev/helpers/project.js +13 -8
  57. package/lib/projects/localDev/localDevWebsocketServerUtils.d.ts +8 -7
  58. package/lib/projects/platformVersion.d.ts +8 -0
  59. package/lib/projects/platformVersion.js +31 -2
  60. package/lib/prompts/accountsPrompt.d.ts +2 -1
  61. package/lib/prompts/accountsPrompt.js +10 -2
  62. package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +20 -3
  63. package/mcp-server/tools/project/AddFeatureToProjectTool.js +6 -10
  64. package/mcp-server/tools/project/CreateProjectTool.d.ts +24 -4
  65. package/mcp-server/tools/project/CreateProjectTool.js +5 -10
  66. package/mcp-server/tools/project/GetApiUsagePatternsByAppIdTool.js +5 -8
  67. package/mcp-server/tools/project/GetBuildLogsTool.d.ts +2 -2
  68. package/mcp-server/tools/project/GetBuildLogsTool.js +3 -4
  69. package/mcp-server/tools/project/GetBuildStatusTool.d.ts +1 -1
  70. package/mcp-server/tools/project/GetBuildStatusTool.js +3 -4
  71. package/mcp-server/tools/project/GuidedWalkthroughTool.d.ts +6 -1
  72. package/mcp-server/tools/project/GuidedWalkthroughTool.js +1 -6
  73. package/mcp-server/tools/project/constants.d.ts +12 -1
  74. package/mcp-server/tools/project/constants.js +12 -16
  75. package/mcp-server/utils/__tests__/project.test.js +0 -125
  76. package/mcp-server/utils/project.js +0 -8
  77. package/package.json +10 -5
  78. package/types/LocalDev.d.ts +0 -4
  79. package/ui/components/ActionSection.d.ts +12 -0
  80. package/ui/components/ActionSection.js +25 -0
  81. package/ui/components/BoxWithTitle.d.ts +4 -2
  82. package/ui/components/BoxWithTitle.js +2 -2
  83. package/ui/components/FullScreen.d.ts +6 -0
  84. package/ui/components/FullScreen.js +13 -0
  85. package/ui/components/InputField.d.ts +10 -0
  86. package/ui/components/InputField.js +10 -0
  87. package/ui/components/SelectInput.d.ts +11 -0
  88. package/ui/components/SelectInput.js +59 -0
  89. package/ui/components/StatusIcon.d.ts +9 -0
  90. package/ui/components/StatusIcon.js +17 -0
  91. package/ui/components/getStarted/GetStartedFlow.d.ts +8 -0
  92. package/ui/components/getStarted/GetStartedFlow.js +136 -0
  93. package/ui/components/getStarted/reducer.d.ts +59 -0
  94. package/ui/components/getStarted/reducer.js +72 -0
  95. package/ui/components/getStarted/screens/ProjectSetupScreen.d.ts +16 -0
  96. package/ui/components/getStarted/screens/ProjectSetupScreen.js +39 -0
  97. package/ui/components/getStarted/screens/UploadScreen.d.ts +7 -0
  98. package/ui/components/getStarted/screens/UploadScreen.js +43 -0
  99. package/ui/components/getStarted/selectors.d.ts +2 -0
  100. package/ui/components/getStarted/selectors.js +1 -0
  101. package/ui/constants.d.ts +6 -0
  102. package/ui/constants.js +6 -0
  103. package/ui/lib/constants.d.ts +16 -0
  104. package/ui/lib/constants.js +16 -0
  105. package/ui/playground/fixtures.js +47 -0
  106. package/ui/render.d.ts +4 -0
  107. package/ui/render.js +31 -0
  108. package/ui/styles.d.ts +3 -0
  109. package/ui/styles.js +3 -0
package/lib/mcp/setup.js CHANGED
@@ -47,44 +47,23 @@ export async function addMcpServerToConfig(targets) {
47
47
  else {
48
48
  derivedTargets = targets;
49
49
  }
50
- // Prompt for standalone mode
51
- const { useStandaloneMode } = await promptUser({
52
- name: 'useStandaloneMode',
53
- type: 'confirm',
54
- message: commands.mcp.setup.prompts.standaloneMode,
55
- default: false,
56
- });
57
- const mcpCommand = useStandaloneMode
58
- ? {
59
- command: 'npx',
60
- args: [
61
- '-y',
62
- '-p',
63
- '@hubspot/cli@8.0.1-experimental.0',
64
- 'hs',
65
- 'mcp',
66
- 'start',
67
- ],
68
- env: { HUBSPOT_MCP_STANDALONE: 'true' },
69
- }
70
- : defaultMcpCommand;
71
50
  if (derivedTargets.includes(claudeCode)) {
72
- await runSetupFunction(() => setupClaudeCode(mcpCommand));
51
+ await runSetupFunction(setupClaudeCode);
73
52
  }
74
53
  if (derivedTargets.includes(cursor)) {
75
- await runSetupFunction(() => setupCursor(mcpCommand));
54
+ await runSetupFunction(setupCursor);
76
55
  }
77
56
  if (derivedTargets.includes(windsurf)) {
78
- await runSetupFunction(() => setupWindsurf(mcpCommand));
57
+ await runSetupFunction(setupWindsurf);
79
58
  }
80
59
  if (derivedTargets.includes(vscode)) {
81
- await runSetupFunction(() => setupVsCode(mcpCommand));
60
+ await runSetupFunction(setupVsCode);
82
61
  }
83
62
  if (derivedTargets.includes(codex)) {
84
- await runSetupFunction(() => setupCodex(mcpCommand));
63
+ await runSetupFunction(setupCodex);
85
64
  }
86
65
  if (derivedTargets.includes(gemini)) {
87
- await runSetupFunction(() => setupGemini(mcpCommand));
66
+ await runSetupFunction(setupGemini);
88
67
  }
89
68
  uiLogger.info(commands.mcp.setup.success(derivedTargets));
90
69
  return derivedTargets;
@@ -143,14 +122,9 @@ function setupMcpConfigFile(config) {
143
122
  mcpConfig.mcpServers = {};
144
123
  }
145
124
  // Add or update HubSpot CLI MCP server
146
- const serverConfig = {
147
- command: config.mcpCommand.command,
148
- args: config.mcpCommand.args,
125
+ mcpConfig.mcpServers[mcpServerName] = {
126
+ ...config.mcpCommand,
149
127
  };
150
- if (config.mcpCommand.env) {
151
- serverConfig.env = config.mcpCommand.env;
152
- }
153
- mcpConfig.mcpServers[mcpServerName] = serverConfig;
154
128
  // Write the updated config
155
129
  fs.writeFileSync(config.configPath, JSON.stringify(mcpConfig, null, 2));
156
130
  SpinniesManager.succeed('spinner', {
@@ -171,16 +145,10 @@ export async function setupVsCode(mcpCommand = defaultMcpCommand) {
171
145
  SpinniesManager.add('vsCode', {
172
146
  text: commands.mcp.setup.spinners.configuringVsCode,
173
147
  });
174
- const commandWithAgent = buildCommandWithAgentString(mcpCommand, vscode);
175
- const configObject = {
148
+ const mcpConfig = JSON.stringify({
176
149
  name: mcpServerName,
177
- command: commandWithAgent.command,
178
- args: commandWithAgent.args,
179
- };
180
- if (commandWithAgent.env) {
181
- configObject.env = commandWithAgent.env;
182
- }
183
- const mcpConfig = JSON.stringify(configObject);
150
+ ...buildCommandWithAgentString(mcpCommand, vscode),
151
+ });
184
152
  await execAsync(`code --add-mcp ${JSON.stringify(mcpConfig)}`);
185
153
  SpinniesManager.succeed('vsCode', {
186
154
  text: commands.mcp.setup.spinners.configuredVsCode,
@@ -211,44 +179,30 @@ export async function setupClaudeCode(mcpCommand = defaultMcpCommand) {
211
179
  try {
212
180
  // Check if claude command is available
213
181
  await execAsync('claude --version');
214
- // Run claude mcp add command
215
- const commandWithAgent = buildCommandWithAgentString(mcpCommand, claudeCode);
216
- const configObject = {
217
- type: 'stdio',
218
- command: commandWithAgent.command,
219
- args: commandWithAgent.args,
220
- };
221
- if (commandWithAgent.env) {
222
- configObject.env = commandWithAgent.env;
223
- }
224
- const mcpConfig = JSON.stringify(configObject);
225
- const { stdout } = await execAsync('claude mcp list');
226
- if (stdout.includes(mcpServerName)) {
227
- SpinniesManager.update('claudeCode', {
228
- text: commands.mcp.setup.spinners.alreadyInstalled,
229
- });
230
- await execAsync(`claude mcp remove "${mcpServerName}" --scope user`);
231
- }
232
- await execAsync(`claude mcp add-json "${mcpServerName}" ${JSON.stringify(mcpConfig)} --scope user`);
233
- SpinniesManager.succeed('claudeCode', {
234
- text: commands.mcp.setup.spinners.configuredClaudeCode,
235
- });
236
- return true;
237
182
  }
238
- catch (error) {
239
- if (error instanceof Error && error.message.includes('claude')) {
240
- SpinniesManager.fail('claudeCode', {
241
- text: commands.mcp.setup.spinners.claudeCodeNotFound,
242
- });
243
- }
244
- else {
245
- SpinniesManager.fail('claudeCode', {
246
- text: commands.mcp.setup.spinners.claudeCodeInstallFailed,
247
- });
248
- logError(error);
249
- }
183
+ catch (e) {
184
+ SpinniesManager.fail('claudeCode', {
185
+ text: commands.mcp.setup.spinners.claudeCodeNotFound,
186
+ });
250
187
  return false;
251
188
  }
189
+ // Run claude mcp add command
190
+ const mcpConfig = JSON.stringify({
191
+ type: 'stdio',
192
+ ...buildCommandWithAgentString(mcpCommand, claudeCode),
193
+ });
194
+ const { stdout } = await execAsync('claude mcp list');
195
+ if (stdout.includes(mcpServerName)) {
196
+ SpinniesManager.update('claudeCode', {
197
+ text: commands.mcp.setup.spinners.alreadyInstalled,
198
+ });
199
+ await execAsync(`claude mcp remove "${mcpServerName}" --scope user`);
200
+ }
201
+ await execAsync(`claude mcp add-json "${mcpServerName}" ${JSON.stringify(mcpConfig)} --scope user`);
202
+ SpinniesManager.succeed('claudeCode', {
203
+ text: commands.mcp.setup.spinners.configuredClaudeCode,
204
+ });
205
+ return true;
252
206
  }
253
207
  catch (error) {
254
208
  SpinniesManager.fail('claudeCode', {
@@ -283,8 +237,16 @@ export async function setupCodex(mcpCommand = defaultMcpCommand) {
283
237
  SpinniesManager.add('codexSpinner', {
284
238
  text: commands.mcp.setup.spinners.configuringCodex,
285
239
  });
286
- // Check if codex command is available
287
- await execAsync('codex --version');
240
+ try {
241
+ // Check if codex command is available
242
+ await execAsync('codex --version');
243
+ }
244
+ catch (error) {
245
+ SpinniesManager.fail('codexSpinner', {
246
+ text: commands.mcp.setup.spinners.codexNotFound,
247
+ });
248
+ return false;
249
+ }
288
250
  const mcpCommandWithAgent = buildCommandWithAgentString(mcpCommand, codex);
289
251
  await execAsync(`codex mcp add "${mcpServerName}" -- ${mcpCommandWithAgent.command} ${mcpCommandWithAgent.args.join(' ')}`);
290
252
  SpinniesManager.succeed('codexSpinner', {
@@ -293,17 +255,10 @@ export async function setupCodex(mcpCommand = defaultMcpCommand) {
293
255
  return true;
294
256
  }
295
257
  catch (error) {
296
- if (error instanceof Error && error.message.includes('codex')) {
297
- SpinniesManager.fail('codexSpinner', {
298
- text: commands.mcp.setup.spinners.codexNotFound,
299
- });
300
- }
301
- else {
302
- SpinniesManager.fail('codexSpinner', {
303
- text: commands.mcp.setup.spinners.codexInstallFailed,
304
- });
305
- logError(error);
306
- }
258
+ SpinniesManager.fail('codexSpinner', {
259
+ text: commands.mcp.setup.spinners.codexInstallFailed,
260
+ });
261
+ logError(error);
307
262
  return false;
308
263
  }
309
264
  }
@@ -312,7 +267,15 @@ export async function setupGemini(mcpCommand = defaultMcpCommand) {
312
267
  SpinniesManager.add('geminiSpinner', {
313
268
  text: commands.mcp.setup.spinners.configuringGemini,
314
269
  });
315
- await execAsync('gemini --version');
270
+ try {
271
+ await execAsync('gemini --version');
272
+ }
273
+ catch (e) {
274
+ SpinniesManager.fail('geminiSpinner', {
275
+ text: commands.mcp.setup.spinners.geminiNotFound,
276
+ });
277
+ return false;
278
+ }
316
279
  const mcpCommandWithAgent = buildCommandWithAgentString(mcpCommand, gemini);
317
280
  await execAsync(`gemini mcp add -s user "${mcpServerName}" ${mcpCommandWithAgent.command} ${mcpCommandWithAgent.args.join(' ')}`);
318
281
  SpinniesManager.succeed('geminiSpinner', {
@@ -321,17 +284,10 @@ export async function setupGemini(mcpCommand = defaultMcpCommand) {
321
284
  return true;
322
285
  }
323
286
  catch (error) {
324
- if (error instanceof Error && error.message.includes('gemini')) {
325
- SpinniesManager.fail('geminiSpinner', {
326
- text: commands.mcp.setup.spinners.geminiNotFound,
327
- });
328
- }
329
- else {
330
- SpinniesManager.fail('geminiSpinner', {
331
- text: commands.mcp.setup.spinners.geminiInstallFailed,
332
- });
333
- logError(error);
334
- }
287
+ SpinniesManager.fail('geminiSpinner', {
288
+ text: commands.mcp.setup.spinners.geminiInstallFailed,
289
+ });
290
+ logError(error);
335
291
  return false;
336
292
  }
337
293
  }
@@ -1,10 +1,18 @@
1
- import { AppFunctionComponentMetadata } from '@hubspot/local-dev-lib/types/ComponentStructure';
1
+ import { ProjectConfig } from '../../types/Projects.js';
2
+ type FunctionInfo = {
3
+ componentName: string;
4
+ appId: number;
5
+ endpoint?: {
6
+ path: string;
7
+ };
8
+ };
2
9
  declare class _ProjectLogsManager {
3
10
  projectName: string | undefined;
11
+ projectConfig: ProjectConfig | undefined;
4
12
  projectId: number | undefined;
5
13
  accountId: number | undefined;
6
- functions: AppFunctionComponentMetadata[];
7
- selectedFunction: AppFunctionComponentMetadata | undefined;
14
+ functions: FunctionInfo[];
15
+ selectedFunction: FunctionInfo | undefined;
8
16
  functionName: string | undefined;
9
17
  appId: number | undefined;
10
18
  isPublicFunction: boolean | undefined;
@@ -13,6 +21,7 @@ declare class _ProjectLogsManager {
13
21
  constructor();
14
22
  init(accountId: number): Promise<void>;
15
23
  fetchFunctionDetails(): Promise<void>;
24
+ fetchFunctionDetailsV2(deployedBuildId: number): Promise<void>;
16
25
  getFunctionNames(): string[];
17
26
  setFunction(functionName?: string): void;
18
27
  }
@@ -1,10 +1,15 @@
1
1
  import { getProjectConfig } from './config.js';
2
2
  import { ensureProjectExists } from './ensureProjectExists.js';
3
3
  import { fetchProjectComponentsMetadata } from '@hubspot/local-dev-lib/api/projects';
4
+ import { fetchAppMetadataBySourceId } from '@hubspot/local-dev-lib/api/appsDev';
4
5
  import { uiLogger } from '../ui/logger.js';
5
6
  import { commands } from '../../lang/en.js';
7
+ import { isV2Project } from './platformVersion.js';
8
+ import { getDeployedProjectNodes } from './localDev/helpers/project.js';
9
+ import { debugError } from '../errorHandlers/index.js';
6
10
  class _ProjectLogsManager {
7
11
  projectName;
12
+ projectConfig;
8
13
  projectId;
9
14
  accountId;
10
15
  functions;
@@ -15,6 +20,7 @@ class _ProjectLogsManager {
15
20
  endpointName;
16
21
  reset() {
17
22
  this.projectName = undefined;
23
+ this.projectConfig = undefined;
18
24
  this.projectId = undefined;
19
25
  this.accountId = undefined;
20
26
  this.functions = [];
@@ -32,8 +38,8 @@ class _ProjectLogsManager {
32
38
  if (!projectConfig || !projectConfig.name) {
33
39
  throw new Error(commands.project.logs.errors.noProjectConfig);
34
40
  }
35
- const { name: projectName } = projectConfig;
36
- this.projectName = projectName;
41
+ this.projectConfig = projectConfig;
42
+ this.projectName = projectConfig.name;
37
43
  this.accountId = accountId;
38
44
  this.functions = [];
39
45
  const { project } = await ensureProjectExists(this.accountId, this.projectName, {
@@ -45,7 +51,16 @@ class _ProjectLogsManager {
45
51
  throw new Error(commands.project.logs.errors.failedToFetchProjectDetails);
46
52
  }
47
53
  this.projectId = project.id;
48
- await this.fetchFunctionDetails();
54
+ if (isV2Project(projectConfig.platformVersion)) {
55
+ const deployedBuildId = project.deployedBuild.buildId;
56
+ if (!deployedBuildId) {
57
+ throw new Error(commands.project.logs.errors.noDeployedBuild);
58
+ }
59
+ await this.fetchFunctionDetailsV2(deployedBuildId);
60
+ }
61
+ else {
62
+ await this.fetchFunctionDetails();
63
+ }
49
64
  }
50
65
  async fetchFunctionDetails() {
51
66
  if (!this.projectId) {
@@ -61,14 +76,60 @@ class _ProjectLogsManager {
61
76
  return type && type.name === 'PRIVATE_APP';
62
77
  });
63
78
  apps.forEach(app => {
64
- this.functions.push(
65
- // If component type is APP_FUNCTION, we can safely cast as AppFunctionComponentMetadata
66
- ...app.featureComponents.filter(component => component.type.name === 'APP_FUNCTION'));
79
+ const appFunctions = app.featureComponents.filter(component => component.type.name === 'APP_FUNCTION');
80
+ appFunctions.forEach(fn => {
81
+ if (fn.deployOutput) {
82
+ this.functions.push({
83
+ componentName: fn.componentName,
84
+ appId: fn.deployOutput.appId,
85
+ endpoint: fn.deployOutput.endpoint,
86
+ });
87
+ }
88
+ });
67
89
  });
68
90
  if (this.functions.length === 0) {
69
91
  throw new Error(commands.project.logs.errors.noFunctionsInProject);
70
92
  }
71
93
  }
94
+ async fetchFunctionDetailsV2(deployedBuildId) {
95
+ if (!this.projectId || !this.accountId || !this.projectConfig) {
96
+ uiLogger.debug(commands.project.logs.errors.projectLogsManagerNotInitialized);
97
+ throw new Error(commands.project.logs.errors.generic);
98
+ }
99
+ let deployedNodes;
100
+ try {
101
+ deployedNodes = await getDeployedProjectNodes(this.projectConfig, this.accountId, deployedBuildId);
102
+ }
103
+ catch (err) {
104
+ debugError(err);
105
+ throw new Error(commands.project.logs.errors.failedToFetchProjectDetails);
106
+ }
107
+ const appNode = Object.values(deployedNodes).find(node => node.componentType === 'APPLICATION');
108
+ if (!appNode) {
109
+ throw new Error(commands.project.logs.errors.noFunctionsInProject);
110
+ }
111
+ let appId;
112
+ try {
113
+ const { data: appMetadata } = await fetchAppMetadataBySourceId(this.projectId, appNode.uid, this.accountId);
114
+ appId = appMetadata.id;
115
+ }
116
+ catch (err) {
117
+ debugError(err);
118
+ throw new Error(commands.project.logs.errors.failedToFetchProjectDetails);
119
+ }
120
+ const functionNodes = Object.values(deployedNodes).filter(node => node.componentType === 'APP_FUNCTION');
121
+ for (const fnNode of functionNodes) {
122
+ const config = fnNode.config;
123
+ this.functions.push({
124
+ componentName: fnNode.uid,
125
+ appId,
126
+ endpoint: config.endpoint,
127
+ });
128
+ }
129
+ if (this.functions.length === 0) {
130
+ throw new Error(commands.project.logs.errors.noFunctionsInProject);
131
+ }
132
+ }
72
133
  getFunctionNames() {
73
134
  return this.functions.map(serverlessFunction => serverlessFunction.componentName);
74
135
  }
@@ -81,12 +142,9 @@ class _ProjectLogsManager {
81
142
  throw new Error(commands.project.logs.errors.noFunctionWithName(functionName));
82
143
  }
83
144
  this.functionName = functionName;
84
- if (!this.selectedFunction.deployOutput) {
85
- throw new Error(commands.project.logs.errors.functionNotDeployed(functionName));
86
- }
87
- this.appId = this.selectedFunction.deployOutput.appId;
88
- if (this.selectedFunction.deployOutput.endpoint) {
89
- this.endpointName = this.selectedFunction.deployOutput.endpoint.path;
145
+ this.appId = this.selectedFunction.appId;
146
+ if (this.selectedFunction.endpoint) {
147
+ this.endpointName = this.selectedFunction.endpoint.path;
90
148
  this.isPublicFunction = true;
91
149
  }
92
150
  else {