@hubspot/cli 8.11.0-beta.0 → 8.12.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 (57) hide show
  1. package/commands/account/clean.js +1 -1
  2. package/commands/account/list.js +1 -1
  3. package/commands/account/remove.js +1 -1
  4. package/commands/account/rename.js +1 -1
  5. package/commands/account/use.js +1 -1
  6. package/commands/api.d.ts +4 -1
  7. package/commands/api.js +11 -14
  8. package/commands/project/appInstallStatus.d.ts +2 -1
  9. package/commands/project/appInstallStatus.js +19 -17
  10. package/commands/project/create.js +0 -1
  11. package/commands/project/deploy.d.ts +2 -1
  12. package/commands/project/deploy.js +31 -14
  13. package/commands/project/dev/index.js +18 -64
  14. package/commands/project/info.d.ts +2 -1
  15. package/commands/project/info.js +8 -6
  16. package/commands/project/installApp.d.ts +2 -1
  17. package/commands/project/installApp.js +25 -26
  18. package/commands/project/list.js +1 -1
  19. package/commands/project/release/create.d.ts +2 -1
  20. package/commands/project/release/create.js +68 -69
  21. package/commands/project/release/info.d.ts +2 -1
  22. package/commands/project/release/info.js +7 -6
  23. package/commands/project/release/list.d.ts +2 -1
  24. package/commands/project/release/list.js +14 -6
  25. package/commands/project/upload.d.ts +2 -1
  26. package/commands/project/upload.js +23 -20
  27. package/commands/project.js +2 -2
  28. package/commands/testAccount/create.d.ts +2 -1
  29. package/commands/testAccount/create.js +7 -7
  30. package/lang/en.d.ts +21 -28
  31. package/lang/en.js +30 -37
  32. package/lib/commonOpts.js +6 -1
  33. package/lib/constants.d.ts +1 -0
  34. package/lib/constants.js +1 -0
  35. package/lib/jsonOutput.d.ts +109 -0
  36. package/lib/jsonOutput.js +94 -0
  37. package/lib/projects/builds.d.ts +2 -0
  38. package/lib/projects/builds.js +22 -0
  39. package/lib/projects/localDev/DevSessionManager.d.ts +2 -2
  40. package/lib/projects/localDev/DevSessionManager.js +4 -30
  41. package/lib/projects/localDev/helpers/account.d.ts +0 -7
  42. package/lib/projects/localDev/helpers/account.js +1 -80
  43. package/lib/projects/release.d.ts +4 -0
  44. package/lib/projects/release.js +90 -0
  45. package/lib/yargs/makeWrappedYargsHandler.d.ts +5 -1
  46. package/lib/yargs/makeWrappedYargsHandler.js +123 -65
  47. package/mcp-server/Tool.js +32 -26
  48. package/mcp-server/utils/logger.d.ts +3 -0
  49. package/mcp-server/utils/logger.js +30 -0
  50. package/package.json +10 -8
  51. package/types/Yargs.d.ts +3 -1
  52. package/commands/project/dev/deprecatedFlow.d.ts +0 -11
  53. package/commands/project/dev/deprecatedFlow.js +0 -180
  54. package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +0 -43
  55. package/lib/projects/localDev/DevServerManager_DEPRECATED.js +0 -128
  56. package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +0 -64
  57. package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +0 -394
@@ -1,394 +0,0 @@
1
- import path from 'path';
2
- import chokidar from 'chokidar';
3
- import chalk from 'chalk';
4
- import { fetchAppInstallationData } from '@hubspot/local-dev-lib/api/localDevAuth';
5
- import { fetchPublicAppsForPortal, fetchPublicAppProductionInstallCounts, } from '@hubspot/local-dev-lib/api/appsDev';
6
- import { getConfigDefaultAccountIfExists } from '@hubspot/local-dev-lib/config';
7
- import { PROJECT_CONFIG_FILE } from '../../constants.js';
8
- import SpinniesManager from '../../ui/SpinniesManager.js';
9
- import DevServerManager_DEPRECATED from './DevServerManager_DEPRECATED.js';
10
- import DevSessionManager from './DevSessionManager.js';
11
- import { EXIT_CODES } from '../../enums/exitCodes.js';
12
- import { getAccountHomeUrl } from '../urls.js';
13
- import { getErrorMessage } from '../../errorHandlers/index.js';
14
- import { componentIsApp, componentIsPublicApp, CONFIG_FILES, getAppCardConfigs, getComponentUid, } from '../structure.js';
15
- import { ComponentTypes, } from '../../../types/Projects.js';
16
- import { UI_COLORS, uiCommandReference, uiAccountDescription, uiLink, uiLine, } from '../../ui/index.js';
17
- import { logError } from '../../errorHandlers/index.js';
18
- import { isPromptExitError } from '../../errors/PromptExitError.js';
19
- import { installAppBrowserPrompt } from '../../prompts/installAppPrompt.js';
20
- import { confirmPrompt } from '../../prompts/promptUtils.js';
21
- import { handleKeypress } from '../../process.js';
22
- import { lib } from '../../../lang/en.js';
23
- import { uiLogger } from '../../ui/logger.js';
24
- import { getOauthAppInstallUrl } from '../../app/urls.js';
25
- const WATCH_EVENTS = {
26
- add: 'add',
27
- change: 'change',
28
- unlink: 'unlink',
29
- unlinkDir: 'unlinkDir',
30
- };
31
- class LocalDevManager_DEPRECATED {
32
- targetAccountId;
33
- targetProjectAccountId;
34
- projectConfig;
35
- projectDir;
36
- projectId;
37
- debug;
38
- deployedBuild;
39
- isGithubLinked;
40
- watcher;
41
- uploadWarnings;
42
- runnableComponents;
43
- activeApp;
44
- activePublicAppData;
45
- env;
46
- publicAppActiveInstalls;
47
- projectSourceDir;
48
- mostRecentUploadWarning;
49
- devSessionManager;
50
- exit;
51
- port;
52
- constructor(options) {
53
- this.targetAccountId = options.targetAccountId;
54
- // The account that the project exists in. This is not always the targetAccountId
55
- this.targetProjectAccountId = options.parentAccountId;
56
- this.projectConfig = options.projectConfig;
57
- this.projectDir = options.projectDir;
58
- this.projectId = options.projectId;
59
- this.debug = options.debug || false;
60
- this.deployedBuild = options.deployedBuild;
61
- this.isGithubLinked = options.isGithubLinked;
62
- this.watcher = null;
63
- this.uploadWarnings = {};
64
- this.runnableComponents = options.runnableComponents;
65
- this.activeApp = null;
66
- this.activePublicAppData = null;
67
- this.env = options.env;
68
- this.publicAppActiveInstalls = null;
69
- this.mostRecentUploadWarning = null;
70
- this.exit = options.exit;
71
- this.port = options.port;
72
- this.projectSourceDir = path.join(this.projectDir, this.projectConfig.srcDir);
73
- if (!this.targetAccountId || !this.projectConfig || !this.projectDir) {
74
- uiLogger.error(lib.LocalDevManager.failedToInitialize);
75
- throw new Error(lib.LocalDevManager.failedToInitialize);
76
- }
77
- this.devSessionManager = new DevSessionManager({
78
- targetTestingAccountId: this.targetAccountId,
79
- exit: this.exit,
80
- });
81
- }
82
- async setActiveApp(appUid) {
83
- if (!appUid) {
84
- uiLogger.error(lib.LocalDevManager.missingUid);
85
- return this.exit(EXIT_CODES.ERROR);
86
- }
87
- this.activeApp =
88
- this.runnableComponents.find(component => {
89
- return getComponentUid(component) === appUid;
90
- }) || null;
91
- if (componentIsPublicApp(this.activeApp)) {
92
- try {
93
- await this.setActivePublicAppData();
94
- await this.checkActivePublicAppInstalls();
95
- await this.checkPublicAppInstallation();
96
- }
97
- catch (e) {
98
- if (isPromptExitError(e)) {
99
- throw e;
100
- }
101
- logError(e);
102
- }
103
- }
104
- }
105
- async setActivePublicAppData() {
106
- if (!this.activeApp) {
107
- return;
108
- }
109
- const { data: { results: portalPublicApps }, } = await fetchPublicAppsForPortal(this.targetProjectAccountId);
110
- const activePublicAppData = portalPublicApps.find(({ sourceId }) => sourceId === getComponentUid(this.activeApp));
111
- if (!activePublicAppData) {
112
- return;
113
- }
114
- const { data: { uniquePortalInstallCount }, } = await fetchPublicAppProductionInstallCounts(activePublicAppData.id, this.targetProjectAccountId);
115
- this.activePublicAppData = activePublicAppData;
116
- this.publicAppActiveInstalls = uniquePortalInstallCount;
117
- }
118
- async checkActivePublicAppInstalls() {
119
- if (!this.activePublicAppData ||
120
- !this.publicAppActiveInstalls ||
121
- this.publicAppActiveInstalls < 1) {
122
- return;
123
- }
124
- uiLine();
125
- uiLogger.warn(lib.LocalDevManager.activeInstallWarning.installCount(this.activePublicAppData.name, this.publicAppActiveInstalls));
126
- uiLogger.log(lib.LocalDevManager.activeInstallWarning.explanation);
127
- uiLine();
128
- const proceed = await confirmPrompt(lib.LocalDevManager.activeInstallWarning.confirmationPrompt, { defaultAnswer: false });
129
- if (!proceed) {
130
- return this.exit(EXIT_CODES.SUCCESS);
131
- }
132
- }
133
- async start() {
134
- SpinniesManager.stopAll();
135
- SpinniesManager.init();
136
- // Local dev currently relies on the existence of a deployed build in the target account
137
- if (!this.deployedBuild) {
138
- uiLogger.error(lib.LocalDevManager.noDeployedBuild(this.projectConfig.name, uiAccountDescription(this.targetProjectAccountId), this.getUploadCommand()));
139
- uiLogger.log('');
140
- return this.exit(EXIT_CODES.SUCCESS);
141
- }
142
- const setupSucceeded = await this.devServerSetup();
143
- if (!setupSucceeded) {
144
- return this.exit(EXIT_CODES.ERROR);
145
- }
146
- else if (!this.debug) {
147
- console.clear();
148
- }
149
- uiLogger.log(lib.LocalDevManager.headerMessage);
150
- uiLogger.log(uiLink(lib.LocalDevManager.learnMoreLocalDevServer, 'https://developers.hubspot.com/docs/developer-tooling/local-development/hubspot-cli/project-commands'));
151
- uiLogger.log('');
152
- uiLogger.log(chalk.hex(UI_COLORS.SORBET)(lib.LocalDevManager.running(this.projectConfig.name, uiAccountDescription(this.targetAccountId))));
153
- uiLogger.log(lib.LocalDevManager.viewProjectLink(this.projectConfig.name, this.targetProjectAccountId));
154
- if (this.activeApp?.type === ComponentTypes.PublicApp) {
155
- uiLogger.log(uiLink(lib.LocalDevManager.viewTestAccountLink, getAccountHomeUrl(this.targetAccountId)));
156
- }
157
- uiLogger.log('');
158
- uiLogger.log(lib.LocalDevManager.quitHelper);
159
- uiLine();
160
- uiLogger.log('');
161
- await this.devServerStart();
162
- const devSessionRegistered = await this.devSessionManager.registerSession();
163
- if (!devSessionRegistered) {
164
- return this.exit(EXIT_CODES.ERROR);
165
- }
166
- // Initialize project file watcher to detect configuration file changes
167
- this.startWatching();
168
- this.updateKeypressListeners();
169
- this.monitorConsoleOutput();
170
- // Verify that there are no mismatches between components in the local project
171
- // and components in the deployed build of the project.
172
- this.compareLocalProjectToDeployed();
173
- }
174
- async stop(showProgress = true) {
175
- if (showProgress) {
176
- SpinniesManager.add('cleanupMessage', {
177
- text: lib.LocalDevManager.exitingStart,
178
- });
179
- }
180
- await this.stopWatching();
181
- const cleanupServersSucceeded = await this.devServerCleanup();
182
- const cleanupSessionSucceeded = await this.devSessionManager.deleteDevSession();
183
- if (!cleanupServersSucceeded || !cleanupSessionSucceeded) {
184
- if (showProgress) {
185
- SpinniesManager.fail('cleanupMessage', {
186
- text: lib.LocalDevManager.exitingFail,
187
- });
188
- }
189
- return this.exit(EXIT_CODES.ERROR);
190
- }
191
- if (showProgress) {
192
- SpinniesManager.succeed('cleanupMessage', {
193
- text: lib.LocalDevManager.exitingSucceed,
194
- });
195
- }
196
- return this.exit(EXIT_CODES.SUCCESS);
197
- }
198
- async checkPublicAppInstallation() {
199
- if (!componentIsPublicApp(this.activeApp) || !this.activePublicAppData) {
200
- return;
201
- }
202
- const { data: { isInstalledWithScopeGroups, previouslyAuthorizedScopeGroups }, } = await fetchAppInstallationData(this.targetAccountId, this.projectId, this.activeApp.config.uid, this.activeApp.config.auth.requiredScopes, this.activeApp.config.auth.optionalScopes);
203
- const isReinstall = previouslyAuthorizedScopeGroups.length > 0;
204
- if (!isInstalledWithScopeGroups) {
205
- const installUrl = getOauthAppInstallUrl({
206
- targetAccountId: this.targetAccountId,
207
- env: this.env,
208
- clientId: this.activePublicAppData.clientId,
209
- scopes: this.activeApp.config.auth.requiredScopes,
210
- redirectUrls: this.activeApp.config.auth.redirectUrls,
211
- });
212
- await installAppBrowserPrompt(installUrl, isReinstall);
213
- }
214
- }
215
- updateKeypressListeners() {
216
- handleKeypress(async (key) => {
217
- if ((key.ctrl && key.name === 'c') || key.name === 'q') {
218
- this.stop();
219
- }
220
- });
221
- }
222
- getUploadCommand() {
223
- const currentDefaultAccount = getConfigDefaultAccountIfExists();
224
- return this.targetProjectAccountId !== currentDefaultAccount?.accountId
225
- ? uiCommandReference(`hs project upload --account=${this.targetProjectAccountId}`)
226
- : uiCommandReference('hs project upload');
227
- }
228
- logUploadWarning(reason) {
229
- let warning;
230
- if (reason) {
231
- warning = reason;
232
- }
233
- else {
234
- warning =
235
- componentIsPublicApp(this.activeApp) &&
236
- this.publicAppActiveInstalls &&
237
- this.publicAppActiveInstalls > 0
238
- ? lib.LocalDevManager.uploadWarning.defaultPublicAppWarning(this.publicAppActiveInstalls, this.publicAppActiveInstalls === 1 ? 'install' : 'installs')
239
- : lib.LocalDevManager.uploadWarning.defaultWarning;
240
- }
241
- // Avoid logging the warning to the console if it is currently the most
242
- // recently logged warning. We do not want to spam the console with the same message.
243
- if (!this.uploadWarnings[warning]) {
244
- uiLogger.log('');
245
- uiLogger.warn(lib.LocalDevManager.uploadWarning.header(warning));
246
- uiLogger.log(lib.LocalDevManager.uploadWarning.stopDev);
247
- if (this.isGithubLinked) {
248
- uiLogger.log(lib.LocalDevManager.uploadWarning.pushToGithub);
249
- }
250
- else {
251
- uiLogger.log(lib.LocalDevManager.uploadWarning.runUpload(this.getUploadCommand()));
252
- }
253
- uiLogger.log(lib.LocalDevManager.uploadWarning.restartDev);
254
- this.mostRecentUploadWarning = warning;
255
- this.uploadWarnings[warning] = true;
256
- }
257
- }
258
- monitorConsoleOutput() {
259
- const originalStdoutWrite = process.stdout.write.bind(process.stdout);
260
- function customStdoutWrite(chunk, encoding, callback) {
261
- // Reset the most recently logged warning
262
- if (this.mostRecentUploadWarning &&
263
- this.uploadWarnings[this.mostRecentUploadWarning]) {
264
- delete this.uploadWarnings[this.mostRecentUploadWarning];
265
- }
266
- if (typeof encoding === 'function') {
267
- return originalStdoutWrite(chunk, callback);
268
- }
269
- return originalStdoutWrite(chunk, encoding, callback);
270
- }
271
- customStdoutWrite.bind(this);
272
- process.stdout.write = customStdoutWrite;
273
- }
274
- compareLocalProjectToDeployed() {
275
- const deployedComponentNames = this.deployedBuild.subbuildStatuses.map(subbuildStatus => subbuildStatus.buildName);
276
- const missingComponents = [];
277
- this.runnableComponents
278
- .filter(componentIsApp)
279
- .forEach(({ type, config, path }) => {
280
- if (Object.values(ComponentTypes).includes(type)) {
281
- const cardConfigs = getAppCardConfigs(config, path);
282
- if (!deployedComponentNames.includes(config.name)) {
283
- missingComponents.push(`${lib.LocalDevManager.uploadWarning.appLabel} ${config.name}`);
284
- }
285
- cardConfigs.forEach(cardConfig => {
286
- if (cardConfig.data &&
287
- cardConfig.data.title &&
288
- !deployedComponentNames.includes(cardConfig.data.title)) {
289
- missingComponents.push(`${lib.LocalDevManager.uploadWarning.uiExtensionLabel} ${cardConfig.data.title}`);
290
- }
291
- });
292
- }
293
- });
294
- if (missingComponents.length) {
295
- this.logUploadWarning(lib.LocalDevManager.uploadWarning.missingComponents(missingComponents.join(', ')));
296
- }
297
- }
298
- startWatching() {
299
- this.watcher = chokidar.watch(this.projectDir, {
300
- ignoreInitial: true,
301
- });
302
- const configPaths = this.runnableComponents
303
- .filter(({ type }) => Object.values(ComponentTypes).includes(type))
304
- .map(component => {
305
- const appConfigPath = path.join(component.path, CONFIG_FILES[component.type]);
306
- return appConfigPath;
307
- });
308
- const projectConfigPath = path.join(this.projectDir, PROJECT_CONFIG_FILE);
309
- configPaths.push(projectConfigPath);
310
- this.watcher.on('add', filePath => {
311
- this.handleWatchEvent(filePath, WATCH_EVENTS.add, configPaths);
312
- });
313
- this.watcher.on('change', filePath => {
314
- this.handleWatchEvent(filePath, WATCH_EVENTS.change, configPaths);
315
- });
316
- this.watcher.on('unlink', filePath => {
317
- this.handleWatchEvent(filePath, WATCH_EVENTS.unlink, configPaths);
318
- });
319
- this.watcher.on('unlinkDir', filePath => {
320
- this.handleWatchEvent(filePath, WATCH_EVENTS.unlinkDir, configPaths);
321
- });
322
- }
323
- async stopWatching() {
324
- await this.watcher?.close();
325
- }
326
- handleWatchEvent(filePath, event, configPaths) {
327
- if (configPaths.includes(filePath)) {
328
- this.logUploadWarning();
329
- }
330
- else {
331
- this.devServerFileChange(filePath, event);
332
- }
333
- }
334
- async devServerSetup() {
335
- try {
336
- await DevServerManager_DEPRECATED.setup({
337
- components: this.runnableComponents,
338
- onUploadRequired: this.logUploadWarning.bind(this),
339
- accountId: this.targetAccountId,
340
- setActiveApp: this.setActiveApp.bind(this),
341
- exit: this.exit,
342
- port: this.port,
343
- });
344
- return true;
345
- }
346
- catch (e) {
347
- if (this.debug) {
348
- uiLogger.error(getErrorMessage(e));
349
- }
350
- uiLogger.error(lib.LocalDevManager.devServer.setupError(getErrorMessage(e)));
351
- return false;
352
- }
353
- }
354
- async devServerStart() {
355
- try {
356
- await DevServerManager_DEPRECATED.start({
357
- accountId: this.targetAccountId,
358
- projectConfig: this.projectConfig,
359
- });
360
- }
361
- catch (e) {
362
- if (this.debug) {
363
- uiLogger.error(getErrorMessage(e));
364
- }
365
- uiLogger.error(lib.LocalDevManager.devServer.startError(getErrorMessage(e)));
366
- return this.exit(EXIT_CODES.ERROR);
367
- }
368
- }
369
- devServerFileChange(filePath, event) {
370
- try {
371
- DevServerManager_DEPRECATED.fileChange({ filePath, event });
372
- }
373
- catch (e) {
374
- if (this.debug) {
375
- uiLogger.error(getErrorMessage(e));
376
- }
377
- uiLogger.error(lib.LocalDevManager.devServer.fileChangeError(getErrorMessage(e)));
378
- }
379
- }
380
- async devServerCleanup() {
381
- try {
382
- await DevServerManager_DEPRECATED.cleanup();
383
- return true;
384
- }
385
- catch (e) {
386
- if (this.debug) {
387
- uiLogger.error(getErrorMessage(e));
388
- }
389
- uiLogger.error(lib.LocalDevManager.devServer.cleanupError(getErrorMessage(e)));
390
- return false;
391
- }
392
- }
393
- }
394
- export default LocalDevManager_DEPRECATED;