@hubspot/cli 8.0.12-experimental.0 → 8.0.12-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.
- package/bin/cli.js +4 -3
- package/commands/account/clean.js +2 -0
- package/commands/account/createOverride.js +3 -0
- package/commands/account/info.js +34 -16
- package/commands/account/link.js +3 -2
- package/commands/account/list.js +29 -71
- package/commands/account/remove.js +2 -0
- package/commands/account/removeOverride.js +3 -0
- package/commands/account/unlink.js +3 -2
- package/commands/account/use.js +71 -1
- package/commands/project/dev/deprecatedFlow.js +20 -2
- package/commands/project/dev/index.js +6 -0
- package/commands/project/dev/unifiedFlow.js +20 -3
- package/commands/project/lint.js +18 -1
- package/commands/project/upload.js +27 -15
- package/lang/en.d.ts +28 -0
- package/lang/en.js +33 -4
- package/lib/constants.d.ts +2 -0
- package/lib/constants.js +4 -0
- package/lib/doctor/Doctor.js +5 -5
- package/lib/link/index.d.ts +4 -0
- package/lib/link/index.js +40 -9
- package/lib/link/linkUtils.d.ts +1 -0
- package/lib/link/linkUtils.js +26 -1
- package/lib/link/warnIfLinkedDirectory.d.ts +1 -0
- package/lib/link/warnIfLinkedDirectory.js +9 -0
- package/lib/projects/localDev/DevServerManager_DEPRECATED.d.ts +2 -1
- package/lib/projects/localDev/DevServerManager_DEPRECATED.js +2 -2
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.d.ts +2 -0
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +3 -0
- package/lib/projects/preview.js +11 -24
- package/lib/projects/uieLinting.d.ts +9 -0
- package/lib/projects/uieLinting.js +45 -1
- package/lib/ui/accountTable.d.ts +8 -0
- package/lib/ui/accountTable.js +67 -0
- package/lib/yargs/parseYargsOrExit.d.ts +4 -0
- package/lib/yargs/parseYargsOrExit.js +25 -0
- package/mcp-server/server.js +8 -4
- package/mcp-server/tools/index.js +2 -0
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +1 -1
- package/mcp-server/tools/project/CreateTestAccountTool.js +1 -1
- package/mcp-server/tools/project/DeployProjectTool.js +1 -1
- package/mcp-server/tools/project/FindProjectsTool.d.ts +15 -0
- package/mcp-server/tools/project/FindProjectsTool.js +60 -0
- package/mcp-server/tools/project/GetBuildLogsTool.js +1 -1
- package/mcp-server/tools/project/GetBuildStatusTool.js +1 -1
- package/mcp-server/tools/project/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/package.json +1 -1
- package/types/Link.d.ts +8 -3
- package/types/Link.js +5 -1
- package/types/PackageJson.d.ts +1 -0
- package/types/Yargs.d.ts +1 -0
|
@@ -18,6 +18,20 @@ import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
|
18
18
|
import { projectProfilePrompt } from '../../lib/prompts/projectProfilePrompt.js';
|
|
19
19
|
const command = 'upload';
|
|
20
20
|
const describe = commands.project.upload.describe;
|
|
21
|
+
async function handlePreview(accountId, projectId, buildId, targetPortalId) {
|
|
22
|
+
if (!projectId) {
|
|
23
|
+
uiLogger.warn(lib.projectPreview.missingProjectId);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const previewResult = await triggerAndPollPreview(accountId, projectId, buildId, targetPortalId);
|
|
27
|
+
if (!previewResult.succeeded) {
|
|
28
|
+
uiLogger.warn(lib.projectPreview.warning);
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
releaseTag: previewResult.releaseTag,
|
|
32
|
+
succeeded: previewResult.succeeded,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
21
35
|
async function handler(args) {
|
|
22
36
|
const { forceCreate, message, derivedAccountId, skipValidation, formatOutputAsJson, profile: profileOption, useEnv: useEnvOption, preview, target: targetPortalId, exit, addUsageMetadata, } = args;
|
|
23
37
|
const jsonOutput = {};
|
|
@@ -92,20 +106,9 @@ async function handler(args) {
|
|
|
92
106
|
await displayWarnLogs(targetAccountId, projectConfig.name, result.buildId);
|
|
93
107
|
}
|
|
94
108
|
if (result && result.succeeded && preview && targetPortalId) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
else {
|
|
99
|
-
const previewResult = await triggerAndPollPreview(targetAccountId, projectId, result.buildId, targetPortalId);
|
|
100
|
-
if (!previewResult.succeeded) {
|
|
101
|
-
uiLogger.warn(lib.projectPreview.warning);
|
|
102
|
-
}
|
|
103
|
-
if (formatOutputAsJson) {
|
|
104
|
-
jsonOutput.preview = {
|
|
105
|
-
releaseTag: previewResult.releaseTag,
|
|
106
|
-
succeeded: previewResult.succeeded,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
+
const previewJson = await handlePreview(targetAccountId, projectId, result.buildId, targetPortalId);
|
|
110
|
+
if (previewJson && formatOutputAsJson) {
|
|
111
|
+
jsonOutput.preview = previewJson;
|
|
109
112
|
}
|
|
110
113
|
}
|
|
111
114
|
if (result && result.succeeded && formatOutputAsJson) {
|
|
@@ -158,10 +161,19 @@ function projectUploadBuilder(yargs) {
|
|
|
158
161
|
target: {
|
|
159
162
|
describe: commands.project.upload.options.target.describe,
|
|
160
163
|
type: 'number',
|
|
164
|
+
requiresArg: true,
|
|
161
165
|
},
|
|
162
166
|
});
|
|
167
|
+
yargs.check(argv => {
|
|
168
|
+
if (argv.preview && argv.target == null) {
|
|
169
|
+
throw new Error(commands.project.upload.errors.previewRequiresTarget);
|
|
170
|
+
}
|
|
171
|
+
if (argv.target != null && !argv.preview) {
|
|
172
|
+
throw new Error(commands.project.upload.errors.targetRequiresPreview);
|
|
173
|
+
}
|
|
174
|
+
return true;
|
|
175
|
+
});
|
|
163
176
|
yargs.conflicts('profile', 'account');
|
|
164
|
-
yargs.implies('preview', 'target');
|
|
165
177
|
yargs.example([
|
|
166
178
|
['$0 project upload', commands.project.upload.examples.default],
|
|
167
179
|
[
|
package/lang/en.d.ts
CHANGED
|
@@ -129,8 +129,12 @@ export declare const commands: {
|
|
|
129
129
|
};
|
|
130
130
|
list: {
|
|
131
131
|
accounts: string;
|
|
132
|
+
allAccounts: string;
|
|
133
|
+
linkedAccounts: string;
|
|
132
134
|
defaultAccountTitle: string;
|
|
135
|
+
linkedDefaultTitle: string;
|
|
133
136
|
currentResolvedDefaultAccount: (accountId: number) => string;
|
|
137
|
+
directory: (dir: string) => string;
|
|
134
138
|
describe: string;
|
|
135
139
|
configPath: (configPath: string) => string;
|
|
136
140
|
overrideFilePathTitle: string;
|
|
@@ -177,6 +181,15 @@ export declare const commands: {
|
|
|
177
181
|
success: {
|
|
178
182
|
defaultAccountUpdated: (accountName: string) => string;
|
|
179
183
|
};
|
|
184
|
+
linked: {
|
|
185
|
+
editingLinkedDefault: (dir: string) => string;
|
|
186
|
+
alreadyDefault: (accountId: number) => string;
|
|
187
|
+
setLinkedDefault: (account: string) => string;
|
|
188
|
+
accountNotLinked: (account: string) => string;
|
|
189
|
+
promptToLink: (account: string) => string;
|
|
190
|
+
settingGlobalDefault: string;
|
|
191
|
+
nonInteractiveNotLinked: (account: string) => string;
|
|
192
|
+
};
|
|
180
193
|
};
|
|
181
194
|
link: {
|
|
182
195
|
describe: string;
|
|
@@ -188,6 +201,9 @@ export declare const commands: {
|
|
|
188
201
|
deprecatedConfigNotSupported: (command: string) => string;
|
|
189
202
|
writeSettingsFailed: (path: string, err: unknown) => string;
|
|
190
203
|
savedToSettings: (path: string) => string;
|
|
204
|
+
usingLinkedAccounts: (settingsPath: string) => string;
|
|
205
|
+
accountAutoLinked: (accountId: number) => string;
|
|
206
|
+
accountAutoLinkFailed: (accountId: number) => string;
|
|
191
207
|
};
|
|
192
208
|
linkingDirectory: (dir: string) => string;
|
|
193
209
|
managingLinkedAccounts: (dir: string) => string;
|
|
@@ -297,6 +313,9 @@ export declare const commands: {
|
|
|
297
313
|
};
|
|
298
314
|
name: (name: string) => string;
|
|
299
315
|
scopeGroups: string;
|
|
316
|
+
linkedDefaultTitle: string;
|
|
317
|
+
settingsPath: (path: string) => string;
|
|
318
|
+
linkedDefault: (account: string) => string;
|
|
300
319
|
};
|
|
301
320
|
clean: {
|
|
302
321
|
describe: string;
|
|
@@ -1500,6 +1519,7 @@ export declare const commands: {
|
|
|
1500
1519
|
projectAccount: string;
|
|
1501
1520
|
testingAccount: string;
|
|
1502
1521
|
account: string;
|
|
1522
|
+
port: string;
|
|
1503
1523
|
};
|
|
1504
1524
|
};
|
|
1505
1525
|
create: {
|
|
@@ -1796,6 +1816,8 @@ export declare const commands: {
|
|
|
1796
1816
|
errors: {
|
|
1797
1817
|
noProjectConfig: string;
|
|
1798
1818
|
projectLockedError: string;
|
|
1819
|
+
previewRequiresTarget: string;
|
|
1820
|
+
targetRequiresPreview: string;
|
|
1799
1821
|
};
|
|
1800
1822
|
options: {
|
|
1801
1823
|
forceCreate: {
|
|
@@ -1927,6 +1949,7 @@ export declare const commands: {
|
|
|
1927
1949
|
loading: {
|
|
1928
1950
|
checking: string;
|
|
1929
1951
|
creatingConfig: string;
|
|
1952
|
+
addingLintScripts: string;
|
|
1930
1953
|
linting: string;
|
|
1931
1954
|
};
|
|
1932
1955
|
noProjectConfig: string;
|
|
@@ -1943,6 +1966,8 @@ export declare const commands: {
|
|
|
1943
1966
|
failedToFetchRemoteEslintConfig: (platformVersion: string) => string;
|
|
1944
1967
|
failedToCreateEslintConfig: (configPath: string) => string;
|
|
1945
1968
|
eslintConfigRequired: string;
|
|
1969
|
+
lintScriptsAdded: (scriptNames: string[], packageJsonPath: string) => string;
|
|
1970
|
+
failedToAddLintScripts: (packageJsonPath: string) => string;
|
|
1946
1971
|
};
|
|
1947
1972
|
updateDeps: {
|
|
1948
1973
|
help: {
|
|
@@ -3061,6 +3086,9 @@ export declare const commands: {
|
|
|
3061
3086
|
};
|
|
3062
3087
|
};
|
|
3063
3088
|
export declare const lib: {
|
|
3089
|
+
linkedDirectory: {
|
|
3090
|
+
warning: (action: string, settingsPath: string) => string;
|
|
3091
|
+
};
|
|
3064
3092
|
parsing: {
|
|
3065
3093
|
unableToParseStringToNumber: string;
|
|
3066
3094
|
};
|
package/lang/en.js
CHANGED
|
@@ -2,6 +2,7 @@ import chalk from 'chalk';
|
|
|
2
2
|
import { mapToUserFriendlyName } from '@hubspot/project-parsing-lib/transform';
|
|
3
3
|
import { PLATFORM_VERSIONS } from '@hubspot/project-parsing-lib/constants';
|
|
4
4
|
import { PERSONAL_ACCESS_KEY_AUTH_METHOD } from '@hubspot/local-dev-lib/constants/auth';
|
|
5
|
+
import { LOCAL_DEV_DEFAULT_PORT } from '../lib/constants.js';
|
|
5
6
|
import { ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME, DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME, GLOBAL_CONFIG_PATH, } from '@hubspot/local-dev-lib/constants/config';
|
|
6
7
|
import { indent, UI_COLORS, uiAccountDescription, uiAuthCommandReference, uiBetaTag, uiCommandReference, uiLink, } from '../lib/ui/index.js';
|
|
7
8
|
import { getLocalDevUiUrl, getProjectDetailUrl, getProjectSettingsUrl, } from '../lib/projects/urls.js';
|
|
@@ -137,8 +138,12 @@ export const commands = {
|
|
|
137
138
|
},
|
|
138
139
|
list: {
|
|
139
140
|
accounts: `${chalk.bold('Accounts')}:`,
|
|
141
|
+
allAccounts: `${chalk.bold('All Accounts')}:`,
|
|
142
|
+
linkedAccounts: `${chalk.bold('Linked Accounts')}:`,
|
|
140
143
|
defaultAccountTitle: `${chalk.bold('Default Account')}`,
|
|
144
|
+
linkedDefaultTitle: `${chalk.bold('Linked Default Account')}`,
|
|
141
145
|
currentResolvedDefaultAccount: (accountId) => `Account: ${uiAccountDescription(accountId)}`,
|
|
146
|
+
directory: (dir) => `Directory: ${dir}`,
|
|
142
147
|
describe: 'List names of accounts defined in config.',
|
|
143
148
|
configPath: (configPath) => `Source: ${configPath}`,
|
|
144
149
|
overrideFilePathTitle: `${chalk.bold('Default Account Override')}`,
|
|
@@ -185,6 +190,15 @@ export const commands = {
|
|
|
185
190
|
success: {
|
|
186
191
|
defaultAccountUpdated: (accountName) => `Default account updated to "${accountName}"`,
|
|
187
192
|
},
|
|
193
|
+
linked: {
|
|
194
|
+
editingLinkedDefault: (dir) => `Editing the default linked account for this directory (not the global default):\n${indent(1)}${dir}`,
|
|
195
|
+
alreadyDefault: (accountId) => `${uiAccountDescription(accountId)} is the only linked account and is already the default.`,
|
|
196
|
+
setLinkedDefault: (account) => `Linked default set to ${chalk.cyan(account)}`,
|
|
197
|
+
accountNotLinked: (account) => `${account} is not linked to this directory.`,
|
|
198
|
+
promptToLink: (account) => `Would you like to link ${account} to this directory?`,
|
|
199
|
+
settingGlobalDefault: 'Setting global default instead.',
|
|
200
|
+
nonInteractiveNotLinked: (account) => `${account} is not linked to this directory. Setting global default instead.`,
|
|
201
|
+
},
|
|
188
202
|
},
|
|
189
203
|
link: {
|
|
190
204
|
describe: 'Link authenticated HubSpot accounts to the current directory',
|
|
@@ -196,6 +210,9 @@ export const commands = {
|
|
|
196
210
|
deprecatedConfigNotSupported: (command) => `${uiCommandReference(command)} does not support deprecated config. Run ${uiCommandReference('hs config migrate')} to migrate to global config. Then re-run ${uiCommandReference(command)}`,
|
|
197
211
|
writeSettingsFailed: (path, err) => `Failed to write to ${path}: ${err}`,
|
|
198
212
|
savedToSettings: (path) => `Saved to ${path}`,
|
|
213
|
+
usingLinkedAccounts: (settingsPath) => `This directory has linked accounts via ${settingsPath}. Only linked accounts will be available for this command. To manage linked accounts, run ${uiCommandReference('hs account link')}.`,
|
|
214
|
+
accountAutoLinked: (accountId) => `Automatically linked ${uiAccountDescription(accountId)} to this directory.`,
|
|
215
|
+
accountAutoLinkFailed: (accountId) => `Could not automatically link ${uiAccountDescription(accountId)} to this directory. Run ${uiCommandReference('hs account link')} to link it manually.`,
|
|
199
216
|
},
|
|
200
217
|
linkingDirectory: (dir) => `Linking HubSpot account(s) for directory:\n${indent(1)}${dir}`,
|
|
201
218
|
managingLinkedAccounts: (dir) => `Managing linked accounts for:\n${indent(1)}${dir}`,
|
|
@@ -305,6 +322,9 @@ export const commands = {
|
|
|
305
322
|
},
|
|
306
323
|
name: (name) => `${chalk.bold('Account name')}: ${name}`,
|
|
307
324
|
scopeGroups: `${chalk.bold('Scopes available')}:`,
|
|
325
|
+
linkedDefaultTitle: `${chalk.bold('Linked Default Account')}`,
|
|
326
|
+
settingsPath: (path) => `Source: ${path}`,
|
|
327
|
+
linkedDefault: (account) => `Account: ${account}`,
|
|
308
328
|
},
|
|
309
329
|
clean: {
|
|
310
330
|
describe: 'Check for inactive accounts and removes them from the CLI config.',
|
|
@@ -1516,6 +1536,7 @@ export const commands = {
|
|
|
1516
1536
|
projectAccount: 'The id of the account to upload your project to. Must be used with --testing-account. Supported on platform versions 2025.2 and newer.',
|
|
1517
1537
|
testingAccount: 'The id of the account to install apps and test on. Must be used with --project-account. Supported on platform versions 2025.2 and newer.',
|
|
1518
1538
|
account: 'The id of the account to upload your project to. Unsupported on platform versions 2025.2 and newer.',
|
|
1539
|
+
port: `The port for the local dev server. Defaults to ${LOCAL_DEV_DEFAULT_PORT}.`,
|
|
1519
1540
|
},
|
|
1520
1541
|
},
|
|
1521
1542
|
create: {
|
|
@@ -1812,6 +1833,8 @@ export const commands = {
|
|
|
1812
1833
|
errors: {
|
|
1813
1834
|
noProjectConfig: 'No project detected. Run this command from a project directory.',
|
|
1814
1835
|
projectLockedError: `Your project is locked. This may mean that another user is running the ${uiCommandReference('hs project dev')} command for this project. If this is you, unlock the project in Projects UI.`,
|
|
1836
|
+
previewRequiresTarget: `${uiCommandReference('--preview')} requires ${uiCommandReference('--target=<portalId>')} to specify the portal to preview on.`,
|
|
1837
|
+
targetRequiresPreview: `${uiCommandReference('--target')} can only be used with ${uiCommandReference('--preview')}.`,
|
|
1815
1838
|
},
|
|
1816
1839
|
options: {
|
|
1817
1840
|
forceCreate: {
|
|
@@ -1943,6 +1966,7 @@ export const commands = {
|
|
|
1943
1966
|
loading: {
|
|
1944
1967
|
checking: 'Checking lint packages and configuration…',
|
|
1945
1968
|
creatingConfig: 'Creating ESLint configuration files…',
|
|
1969
|
+
addingLintScripts: 'Adding lint scripts to package.json files…',
|
|
1946
1970
|
linting: 'Linting…',
|
|
1947
1971
|
},
|
|
1948
1972
|
noProjectConfig: 'No project detected. Run this command from a project directory.',
|
|
@@ -1971,6 +1995,8 @@ export const commands = {
|
|
|
1971
1995
|
failedToFetchRemoteEslintConfig: (platformVersion) => `Could not download the ESLint config from HubSpot project components for platform version ${platformVersion}. Check your network connection and try again, or add eslint.config.js manually.`,
|
|
1972
1996
|
failedToCreateEslintConfig: (configPath) => `Failed to create ESLint configuration at ${configPath}`,
|
|
1973
1997
|
eslintConfigRequired: 'ESLint configuration is required to run the lint command. Run the command again to create the configuration.',
|
|
1998
|
+
lintScriptsAdded: (scriptNames, packageJsonPath) => `Added ${scriptNames.map(s => `"${s}"`).join(' and ')} to ${packageJsonPath}`,
|
|
1999
|
+
failedToAddLintScripts: (packageJsonPath) => `Failed to add lint scripts to ${packageJsonPath}`,
|
|
1974
2000
|
},
|
|
1975
2001
|
updateDeps: {
|
|
1976
2002
|
help: {
|
|
@@ -2433,7 +2459,7 @@ export const commands = {
|
|
|
2433
2459
|
opsLevel: 'Operations Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2434
2460
|
serviceLevel: 'Service Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2435
2461
|
salesLevel: 'Sales Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2436
|
-
contentLevel: '
|
|
2462
|
+
contentLevel: 'Content Hub tier. Options: FREE, STARTER, PROFESSIONAL, ENTERPRISE',
|
|
2437
2463
|
commerceLevel: 'Commerce Hub tier. Options: FREE, PROFESSIONAL, ENTERPRISE',
|
|
2438
2464
|
},
|
|
2439
2465
|
example: (configPath) => `Create a test account from the config file at ${configPath}`,
|
|
@@ -3086,6 +3112,9 @@ export const commands = {
|
|
|
3086
3112
|
},
|
|
3087
3113
|
};
|
|
3088
3114
|
export const lib = {
|
|
3115
|
+
linkedDirectory: {
|
|
3116
|
+
warning: (action, settingsPath) => `This directory has linked accounts via ${settingsPath}. ${uiCommandReference(action)} modifies your global config, not the linked directory settings. Use ${uiCommandReference('hs account link')} to manage linked accounts.\n`,
|
|
3117
|
+
},
|
|
3089
3118
|
parsing: {
|
|
3090
3119
|
unableToParseStringToNumber: 'Unable to parse string to number',
|
|
3091
3120
|
},
|
|
@@ -4062,9 +4091,9 @@ export const lib = {
|
|
|
4062
4091
|
validJson: 'JSON files valid',
|
|
4063
4092
|
},
|
|
4064
4093
|
port: {
|
|
4065
|
-
inUse: (port) => `
|
|
4066
|
-
inUseSecondary: `Make sure it is available before running ${uiCommandReference('hs project dev')}`,
|
|
4067
|
-
available: (port) => `
|
|
4094
|
+
inUse: (port) => `Default port ${port} is in use`,
|
|
4095
|
+
inUseSecondary: `Make sure it is available before running ${uiCommandReference('hs project dev')}, or use ${uiCommandReference('--port')} to specify a different port`,
|
|
4096
|
+
available: (port) => `Default port ${port} available for local development`,
|
|
4068
4097
|
},
|
|
4069
4098
|
projectValidation: {
|
|
4070
4099
|
valid: 'Project configuration and structure is valid',
|
package/lib/constants.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare const FEEDBACK_INTERVAL: 10;
|
|
|
4
4
|
export declare const HUBSPOT_FOLDER: "@hubspot";
|
|
5
5
|
export declare const MARKETPLACE_FOLDER: "@marketplace";
|
|
6
6
|
export declare const DEFAULT_POLLING_DELAY = 2000;
|
|
7
|
+
export declare const PREVIEW_POLL_TIMEOUT: number;
|
|
7
8
|
export declare const PROJECT_CONFIG_FILE: "hsproject.json";
|
|
8
9
|
export declare const PROJECT_BUILD_STATES: {
|
|
9
10
|
readonly BUILDING: "BUILDING";
|
|
@@ -142,3 +143,4 @@ export declare const ACCOUNT_LEVELS: {
|
|
|
142
143
|
};
|
|
143
144
|
export declare const ACCOUNT_LEVEL_CHOICES: readonly ["FREE", "STARTER", "PROFESSIONAL", "ENTERPRISE"];
|
|
144
145
|
export declare const FEEDBACK_URL = "https://developers.hubspot.com/feedback";
|
|
146
|
+
export declare const LOCAL_DEV_DEFAULT_PORT = 4828;
|
package/lib/constants.js
CHANGED
|
@@ -4,6 +4,7 @@ export const FEEDBACK_INTERVAL = 10;
|
|
|
4
4
|
export const HUBSPOT_FOLDER = '@hubspot';
|
|
5
5
|
export const MARKETPLACE_FOLDER = '@marketplace';
|
|
6
6
|
export const DEFAULT_POLLING_DELAY = 2000;
|
|
7
|
+
export const PREVIEW_POLL_TIMEOUT = 5 * 60 * 1000;
|
|
7
8
|
export const PROJECT_CONFIG_FILE = 'hsproject.json';
|
|
8
9
|
export const PROJECT_BUILD_STATES = {
|
|
9
10
|
BUILDING: 'BUILDING',
|
|
@@ -143,3 +144,6 @@ export const ACCOUNT_LEVEL_CHOICES = [
|
|
|
143
144
|
ACCOUNT_LEVELS.ENTERPRISE,
|
|
144
145
|
];
|
|
145
146
|
export const FEEDBACK_URL = 'https://developers.hubspot.com/feedback';
|
|
147
|
+
// TODO: remove this constant and use PORT_MANAGER_SERVER_PORT from
|
|
148
|
+
// @hubspot/local-dev-lib once LDL changes its default to 4828.
|
|
149
|
+
export const LOCAL_DEV_DEFAULT_PORT = 4828;
|
package/lib/doctor/Doctor.js
CHANGED
|
@@ -10,8 +10,8 @@ import fs from 'fs';
|
|
|
10
10
|
import path from 'path';
|
|
11
11
|
import { Diagnosis } from './Diagnosis.js';
|
|
12
12
|
import { DiagnosticInfoBuilder, } from './DiagnosticInfoBuilder.js';
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import { isPortAvailable } from '@hubspot/local-dev-lib/portManager';
|
|
14
|
+
import { LOCAL_DEV_DEFAULT_PORT } from '../constants.js';
|
|
15
15
|
import { accessTokenForPersonalAccessKey,
|
|
16
16
|
// scopesOnAccessToken,
|
|
17
17
|
} from '@hubspot/local-dev-lib/personalAccessKey';
|
|
@@ -322,16 +322,16 @@ export class Doctor {
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
async checkIfPortsAreAvailable() {
|
|
325
|
-
if (await
|
|
325
|
+
if (await isPortAvailable(LOCAL_DEV_DEFAULT_PORT)) {
|
|
326
326
|
this.diagnosis?.addProjectSection({
|
|
327
327
|
type: 'success',
|
|
328
|
-
message: lib.doctor.port.available(
|
|
328
|
+
message: lib.doctor.port.available(LOCAL_DEV_DEFAULT_PORT),
|
|
329
329
|
});
|
|
330
330
|
return;
|
|
331
331
|
}
|
|
332
332
|
this.diagnosis?.addProjectSection({
|
|
333
333
|
type: 'warning',
|
|
334
|
-
message: lib.doctor.port.inUse(
|
|
334
|
+
message: lib.doctor.port.inUse(LOCAL_DEV_DEFAULT_PORT),
|
|
335
335
|
secondaryMessaging: lib.doctor.port.inUseSecondary,
|
|
336
336
|
});
|
|
337
337
|
}
|
package/lib/link/index.d.ts
CHANGED
|
@@ -12,3 +12,7 @@ export declare function handleLinkFlow({ settings, accountOverrideId, args, }: {
|
|
|
12
12
|
accountOverrideId: number | null;
|
|
13
13
|
args: ArgumentsCamelCase<LinkArgs>;
|
|
14
14
|
}): Promise<ActionResult>;
|
|
15
|
+
export declare function handleLinkedUseAction({ state, targetAccountId, }: {
|
|
16
|
+
state: HsSettingsFile;
|
|
17
|
+
targetAccountId?: number;
|
|
18
|
+
}): Promise<ActionResult>;
|
package/lib/link/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getAllConfigAccounts, getConfigDefaultAccountIfExists, } from '@hubspot/local-dev-lib/config';
|
|
2
2
|
import { confirmPrompt } from '../prompts/promptUtils.js';
|
|
3
3
|
import { promptForAccountsToLink, promptForAccountsToUnlink, promptForAction, promptForDefaultAccount, } from './prompts.js';
|
|
4
|
+
import { ACTION_RESULT_STATUS, } from '../../types/Link.js';
|
|
4
5
|
import { getDefaultAccountOverrideFilePath, removeDefaultAccountOverrideFile, } from '@hubspot/local-dev-lib/config/defaultAccountOverride';
|
|
5
6
|
import { ENVIRONMENTS } from '@hubspot/local-dev-lib/constants/environments';
|
|
6
7
|
import { authenticateNewAccount } from '../accountAuth.js';
|
|
@@ -19,7 +20,7 @@ export class ActionHandlers {
|
|
|
19
20
|
}, { eligibleAccounts: [], inEligibleAccounts: [] });
|
|
20
21
|
const toAdd = await promptForAccountsToLink(context, eligibleAccounts, inEligibleAccounts, state.localDefaultAccount);
|
|
21
22
|
const accounts = [...state.accounts, ...toAdd];
|
|
22
|
-
uiLogger.
|
|
23
|
+
uiLogger.info(commands.account.subcommands.link.events.accountsLinked(toAdd.length));
|
|
23
24
|
const overrideFilePath = getDefaultAccountOverrideFilePath();
|
|
24
25
|
if (overrideFilePath &&
|
|
25
26
|
context.accountOverrideId &&
|
|
@@ -32,7 +33,7 @@ export class ActionHandlers {
|
|
|
32
33
|
if (useOverride) {
|
|
33
34
|
uiLogger.success(commands.account.subcommands.link.events.defaultAccountSet(context.accountOverrideId));
|
|
34
35
|
return {
|
|
35
|
-
status:
|
|
36
|
+
status: ACTION_RESULT_STATUS.SUCCESS,
|
|
36
37
|
settings: {
|
|
37
38
|
accounts,
|
|
38
39
|
localDefaultAccount: context.accountOverrideId,
|
|
@@ -45,14 +46,14 @@ export class ActionHandlers {
|
|
|
45
46
|
currentDefault: state.localDefaultAccount,
|
|
46
47
|
});
|
|
47
48
|
return {
|
|
48
|
-
status:
|
|
49
|
+
status: ACTION_RESULT_STATUS.SUCCESS,
|
|
49
50
|
settings: { accounts, localDefaultAccount },
|
|
50
51
|
};
|
|
51
52
|
}
|
|
52
53
|
static async unlink({ state }) {
|
|
53
54
|
const toRemove = await promptForAccountsToUnlink(state.accounts, state.localDefaultAccount);
|
|
54
55
|
if (toRemove.length === 0) {
|
|
55
|
-
return { status:
|
|
56
|
+
return { status: ACTION_RESULT_STATUS.NOOP };
|
|
56
57
|
}
|
|
57
58
|
const remainingAccounts = state.accounts.filter(account => !toRemove.includes(account));
|
|
58
59
|
const defaultWasRemoved = state.localDefaultAccount !== undefined &&
|
|
@@ -61,7 +62,7 @@ export class ActionHandlers {
|
|
|
61
62
|
if (remainingAccounts.length === 0) {
|
|
62
63
|
uiLogger.success(commands.account.subcommands.link.events.noAccountsLinked);
|
|
63
64
|
return {
|
|
64
|
-
status:
|
|
65
|
+
status: ACTION_RESULT_STATUS.SUCCESS,
|
|
65
66
|
settings: {
|
|
66
67
|
accounts: remainingAccounts,
|
|
67
68
|
localDefaultAccount: undefined,
|
|
@@ -73,7 +74,7 @@ export class ActionHandlers {
|
|
|
73
74
|
uiLogger.success(commands.account.subcommands.link.events.accountsUnlinked(toRemove.length));
|
|
74
75
|
uiLogger.success(commands.account.subcommands.link.events.defaultAccountRemains(state.localDefaultAccount));
|
|
75
76
|
return {
|
|
76
|
-
status:
|
|
77
|
+
status: ACTION_RESULT_STATUS.SUCCESS,
|
|
77
78
|
settings: {
|
|
78
79
|
accounts: remainingAccounts,
|
|
79
80
|
localDefaultAccount: state.localDefaultAccount,
|
|
@@ -90,7 +91,7 @@ export class ActionHandlers {
|
|
|
90
91
|
uiLogger.success(commands.account.subcommands.link.events.updatedLinkedAccounts);
|
|
91
92
|
}
|
|
92
93
|
return {
|
|
93
|
-
status:
|
|
94
|
+
status: ACTION_RESULT_STATUS.SUCCESS,
|
|
94
95
|
settings: { accounts: remainingAccounts, localDefaultAccount },
|
|
95
96
|
};
|
|
96
97
|
}
|
|
@@ -101,7 +102,7 @@ export class ActionHandlers {
|
|
|
101
102
|
});
|
|
102
103
|
if (!updatedConfig) {
|
|
103
104
|
return {
|
|
104
|
-
status:
|
|
105
|
+
status: ACTION_RESULT_STATUS.ERROR,
|
|
105
106
|
reason: commands.account.subcommands.link.errors.authFailed,
|
|
106
107
|
};
|
|
107
108
|
}
|
|
@@ -115,7 +116,7 @@ export class ActionHandlers {
|
|
|
115
116
|
}
|
|
116
117
|
static async cancel() {
|
|
117
118
|
return {
|
|
118
|
-
status:
|
|
119
|
+
status: ACTION_RESULT_STATUS.NOOP,
|
|
119
120
|
};
|
|
120
121
|
}
|
|
121
122
|
}
|
|
@@ -152,3 +153,33 @@ async function resolveDefaultAccount({ accounts, currentDefault, prompt = '', })
|
|
|
152
153
|
}
|
|
153
154
|
return promptForDefaultAccount(accounts, currentDefault, prompt);
|
|
154
155
|
}
|
|
156
|
+
export async function handleLinkedUseAction({ state, targetAccountId, }) {
|
|
157
|
+
if (targetAccountId !== undefined) {
|
|
158
|
+
if (state.accounts.includes(targetAccountId)) {
|
|
159
|
+
uiLogger.success(commands.account.subcommands.link.events.defaultAccountSet(targetAccountId));
|
|
160
|
+
return {
|
|
161
|
+
status: ACTION_RESULT_STATUS.SUCCESS,
|
|
162
|
+
settings: {
|
|
163
|
+
accounts: state.accounts,
|
|
164
|
+
localDefaultAccount: targetAccountId,
|
|
165
|
+
},
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
const accounts = [...state.accounts, targetAccountId];
|
|
169
|
+
uiLogger.info(commands.account.subcommands.link.events.accountsLinked(1));
|
|
170
|
+
uiLogger.success(commands.account.subcommands.link.events.defaultAccountSet(targetAccountId));
|
|
171
|
+
return {
|
|
172
|
+
status: ACTION_RESULT_STATUS.SUCCESS,
|
|
173
|
+
settings: { accounts, localDefaultAccount: targetAccountId },
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
const localDefaultAccount = await resolveDefaultAccount({
|
|
177
|
+
accounts: state.accounts,
|
|
178
|
+
currentDefault: state.localDefaultAccount,
|
|
179
|
+
});
|
|
180
|
+
uiLogger.success(commands.account.subcommands.link.events.defaultAccountSet(localDefaultAccount));
|
|
181
|
+
return {
|
|
182
|
+
status: ACTION_RESULT_STATUS.SUCCESS,
|
|
183
|
+
settings: { accounts: state.accounts, localDefaultAccount },
|
|
184
|
+
};
|
|
185
|
+
}
|
package/lib/link/linkUtils.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HsSettingsFile } from '@hubspot/local-dev-lib/types/HsSettings';
|
|
2
2
|
export declare function isDirectoryLinked(settings: HsSettingsFile | null): settings is HsSettingsFile;
|
|
3
3
|
export declare function hasDeprecatedConfigConflict(commandArgs: (string | number)[]): boolean;
|
|
4
|
+
export declare function addAccountToLinkedSettings(accountId: number): void;
|
|
4
5
|
export declare function writeLinkedSettings(settings: HsSettingsFile, settingsPath: string): boolean;
|
package/lib/link/linkUtils.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { localConfigFileExists } from '@hubspot/local-dev-lib/config';
|
|
2
|
-
import { writeHsSettingsFile } from '@hubspot/local-dev-lib/config/hsSettings';
|
|
2
|
+
import { getHsSettingsFileIfExists, writeHsSettingsFile, } from '@hubspot/local-dev-lib/config/hsSettings';
|
|
3
3
|
import { uiLogger } from '../ui/logger.js';
|
|
4
|
+
import { debugError } from '../errorHandlers/index.js';
|
|
4
5
|
import { commands } from '../../lang/en.js';
|
|
5
6
|
export function isDirectoryLinked(settings) {
|
|
6
7
|
return settings !== null && settings.accounts.length > 0;
|
|
@@ -12,6 +13,30 @@ export function hasDeprecatedConfigConflict(commandArgs) {
|
|
|
12
13
|
}
|
|
13
14
|
return false;
|
|
14
15
|
}
|
|
16
|
+
export function addAccountToLinkedSettings(accountId) {
|
|
17
|
+
if (localConfigFileExists()) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const settings = getHsSettingsFileIfExists();
|
|
21
|
+
if (!settings || settings.accounts.length === 0) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (settings.accounts.includes(accountId)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const updated = {
|
|
28
|
+
...settings,
|
|
29
|
+
accounts: [...settings.accounts, accountId],
|
|
30
|
+
};
|
|
31
|
+
try {
|
|
32
|
+
writeHsSettingsFile(updated);
|
|
33
|
+
uiLogger.info(commands.account.subcommands.link.shared.accountAutoLinked(accountId));
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
uiLogger.warn(commands.account.subcommands.link.shared.accountAutoLinkFailed(accountId));
|
|
37
|
+
debugError(err);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
15
40
|
export function writeLinkedSettings(settings, settingsPath) {
|
|
16
41
|
try {
|
|
17
42
|
writeHsSettingsFile(settings);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function warnIfLinkedDirectory(args: (string | number)[]): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { getHsSettingsFilePath } from '@hubspot/local-dev-lib/config/hsSettings';
|
|
2
|
+
import { uiLogger } from '../ui/logger.js';
|
|
3
|
+
import { lib } from '../../lang/en.js';
|
|
4
|
+
export function warnIfLinkedDirectory(args) {
|
|
5
|
+
if (getHsSettingsFilePath() === null) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
uiLogger.warn(lib.linkedDirectory.warning(`hs ${args.join(' ')}`, getHsSettingsFilePath()));
|
|
9
|
+
}
|
|
@@ -21,12 +21,13 @@ declare class DevServerManager_DEPRECATED {
|
|
|
21
21
|
[key: string]: Component;
|
|
22
22
|
}) => Promise<void>): Promise<void>;
|
|
23
23
|
arrangeComponentsByType(components: Component[]): ComponentsByType;
|
|
24
|
-
setup({ components, onUploadRequired, accountId, setActiveApp, exit, }: {
|
|
24
|
+
setup({ components, onUploadRequired, accountId, setActiveApp, exit, port, }: {
|
|
25
25
|
components: Component[];
|
|
26
26
|
onUploadRequired: () => void;
|
|
27
27
|
accountId: number;
|
|
28
28
|
setActiveApp: (appUid: string | undefined) => Promise<void>;
|
|
29
29
|
exit: ExitFunction;
|
|
30
|
+
port?: number;
|
|
30
31
|
}): Promise<void>;
|
|
31
32
|
start({ accountId, projectConfig, }: {
|
|
32
33
|
accountId: number;
|
|
@@ -57,7 +57,7 @@ class DevServerManager_DEPRECATED {
|
|
|
57
57
|
return acc;
|
|
58
58
|
}, {});
|
|
59
59
|
}
|
|
60
|
-
async setup({ components, onUploadRequired, accountId, setActiveApp, exit, }) {
|
|
60
|
+
async setup({ components, onUploadRequired, accountId, setActiveApp, exit, port, }) {
|
|
61
61
|
this.componentsByType = this.arrangeComponentsByType(components);
|
|
62
62
|
let env;
|
|
63
63
|
const accountConfig = getConfigAccountById(accountId);
|
|
@@ -65,7 +65,7 @@ class DevServerManager_DEPRECATED {
|
|
|
65
65
|
env = accountConfig.env;
|
|
66
66
|
}
|
|
67
67
|
try {
|
|
68
|
-
await startPortManagerServer();
|
|
68
|
+
await startPortManagerServer(port);
|
|
69
69
|
}
|
|
70
70
|
catch (e) {
|
|
71
71
|
logError(e);
|
|
@@ -16,6 +16,7 @@ type LocalDevManagerConstructorOptions = {
|
|
|
16
16
|
runnableComponents: Component[];
|
|
17
17
|
env: Environment;
|
|
18
18
|
exit: ExitFunction;
|
|
19
|
+
port?: number;
|
|
19
20
|
};
|
|
20
21
|
declare class LocalDevManager_DEPRECATED {
|
|
21
22
|
targetAccountId: number;
|
|
@@ -39,6 +40,7 @@ declare class LocalDevManager_DEPRECATED {
|
|
|
39
40
|
mostRecentUploadWarning: string | null;
|
|
40
41
|
private devSessionManager;
|
|
41
42
|
private exit;
|
|
43
|
+
private port?;
|
|
42
44
|
constructor(options: LocalDevManagerConstructorOptions);
|
|
43
45
|
setActiveApp(appUid?: string): Promise<void>;
|
|
44
46
|
setActivePublicAppData(): Promise<void>;
|
|
@@ -48,6 +48,7 @@ class LocalDevManager_DEPRECATED {
|
|
|
48
48
|
mostRecentUploadWarning;
|
|
49
49
|
devSessionManager;
|
|
50
50
|
exit;
|
|
51
|
+
port;
|
|
51
52
|
constructor(options) {
|
|
52
53
|
this.targetAccountId = options.targetAccountId;
|
|
53
54
|
// The account that the project exists in. This is not always the targetAccountId
|
|
@@ -67,6 +68,7 @@ class LocalDevManager_DEPRECATED {
|
|
|
67
68
|
this.publicAppActiveInstalls = null;
|
|
68
69
|
this.mostRecentUploadWarning = null;
|
|
69
70
|
this.exit = options.exit;
|
|
71
|
+
this.port = options.port;
|
|
70
72
|
this.projectSourceDir = path.join(this.projectDir, this.projectConfig.srcDir);
|
|
71
73
|
if (!this.targetAccountId || !this.projectConfig || !this.projectDir) {
|
|
72
74
|
uiLogger.error(lib.LocalDevManager.failedToInitialize);
|
|
@@ -337,6 +339,7 @@ class LocalDevManager_DEPRECATED {
|
|
|
337
339
|
accountId: this.targetAccountId,
|
|
338
340
|
setActiveApp: this.setActiveApp.bind(this),
|
|
339
341
|
exit: this.exit,
|
|
342
|
+
port: this.port,
|
|
340
343
|
});
|
|
341
344
|
return true;
|
|
342
345
|
}
|
package/lib/projects/preview.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { triggerAutoRelease, getAutoReleaseStatus, } from '@hubspot/local-dev-lib/api/projects';
|
|
2
|
-
import { DEFAULT_POLLING_DELAY } from '../constants.js';
|
|
2
|
+
import { DEFAULT_POLLING_DELAY, PREVIEW_POLL_TIMEOUT } from '../constants.js';
|
|
3
3
|
import SpinniesManager from '../ui/SpinniesManager.js';
|
|
4
4
|
import { logError, ApiErrorContext } from '../errorHandlers/index.js';
|
|
5
5
|
import { lib } from '../../lang/en.js';
|
|
6
|
-
const PREVIEW_POLL_TIMEOUT = 5 * 60 * 1000;
|
|
7
6
|
export async function triggerAndPollPreview(accountId, projectId, buildId, targetPortalId) {
|
|
8
7
|
let triggerResponse;
|
|
9
8
|
SpinniesManager.add('preview', {
|
|
@@ -46,26 +45,14 @@ export async function triggerAndPollPreview(accountId, projectId, buildId, targe
|
|
|
46
45
|
});
|
|
47
46
|
return { succeeded: true, releaseTag, appId };
|
|
48
47
|
}
|
|
49
|
-
function pollPreviewStatus(accountId, projectId, targetPortalId, expectedReleaseTag, appId) {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
}
|
|
60
|
-
if (Date.now() - startTime >= PREVIEW_POLL_TIMEOUT) {
|
|
61
|
-
clearInterval(pollInterval);
|
|
62
|
-
reject(new Error(lib.projectPreview.timeout));
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
catch (e) {
|
|
66
|
-
clearInterval(pollInterval);
|
|
67
|
-
reject(e);
|
|
68
|
-
}
|
|
69
|
-
}, DEFAULT_POLLING_DELAY);
|
|
70
|
-
});
|
|
48
|
+
async function pollPreviewStatus(accountId, projectId, targetPortalId, expectedReleaseTag, appId) {
|
|
49
|
+
const startTime = Date.now();
|
|
50
|
+
while (Date.now() - startTime < PREVIEW_POLL_TIMEOUT) {
|
|
51
|
+
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLLING_DELAY));
|
|
52
|
+
const { data } = await getAutoReleaseStatus(accountId, projectId, targetPortalId, expectedReleaseTag, appId);
|
|
53
|
+
if (data.status === 'COMPLETE') {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
throw new Error(lib.projectPreview.timeout);
|
|
71
58
|
}
|