@hubspot/cli 8.0.10-experimental.1 → 8.0.10-experimental.3
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/commands/account/auth.js +15 -5
- package/commands/account/use.js +14 -4
- package/commands/auth.js +10 -6
- package/commands/cms/__tests__/watch.test.js +0 -8
- package/commands/cms/function/logs.js +1 -0
- package/commands/cms/theme/preview.js +2 -4
- package/commands/cms/watch.d.ts +0 -1
- package/commands/cms/watch.js +2 -8
- package/commands/feedback.js +1 -1
- package/commands/hubdb/clear.js +4 -0
- package/commands/hubdb/delete.js +4 -0
- package/commands/hubdb/fetch.js +4 -0
- package/commands/init.js +4 -0
- package/commands/mcp/__tests__/start.test.js +8 -1
- package/commands/mcp/setup.js +1 -9
- package/commands/mcp/start.js +0 -1
- package/commands/project/__tests__/create.test.js +1 -1
- package/commands/project/create.js +2 -2
- package/commands/project/dev/index.js +29 -19
- package/commands/project/download.js +5 -1
- package/commands/project/watch.js +15 -2
- package/commands/sandbox/__tests__/create.test.js +1 -48
- package/commands/sandbox/create.js +3 -30
- package/commands/testAccount/create.js +4 -0
- package/lang/en.d.ts +13 -6
- package/lang/en.js +13 -6
- package/lib/__tests__/buildAccount.test.js +1 -52
- package/lib/__tests__/sandboxes.test.js +1 -29
- package/lib/__tests__/serverlessLogs.test.js +79 -64
- package/lib/accountAuth.js +4 -0
- package/lib/buildAccount.d.ts +1 -6
- package/lib/buildAccount.js +9 -42
- package/lib/constants.d.ts +1 -3
- package/lib/constants.js +1 -3
- package/lib/errors/PromptExitError.d.ts +4 -0
- package/lib/errors/PromptExitError.js +8 -0
- package/lib/generateSelectors.js +1 -2
- package/lib/mcp/__tests__/setup.test.js +357 -28
- package/lib/mcp/setup.d.ts +1 -0
- package/lib/mcp/setup.js +77 -30
- package/lib/projects/__tests__/components.test.js +14 -0
- package/lib/projects/components.js +12 -2
- package/lib/projects/create/__tests__/legacy.test.js +6 -24
- package/lib/projects/create/index.js +1 -4
- package/lib/projects/create/legacy.js +3 -8
- package/lib/projects/create/v2.js +1 -9
- package/lib/projects/ensureProjectExists.js +1 -2
- package/lib/projects/localDev/AppDevModeInterface.js +4 -0
- package/lib/projects/localDev/LocalDevManager_DEPRECATED.js +4 -0
- package/lib/projects/localDev/helpers/account.js +5 -11
- package/lib/projects/pollProjectBuildAndDeploy.js +90 -85
- package/lib/projects/upload.d.ts +1 -0
- package/lib/projects/upload.js +37 -46
- package/lib/projects/watch.d.ts +2 -1
- package/lib/projects/watch.js +32 -24
- package/lib/prompts/downloadProjectPrompt.js +11 -10
- package/lib/prompts/installAppPrompt.js +3 -2
- package/lib/prompts/personalAccessKeyPrompt.js +3 -2
- package/lib/prompts/projectDevTargetAccountPrompt.js +13 -16
- package/lib/prompts/selectHubDBTablePrompt.js +8 -4
- package/lib/prompts/selectPublicAppForMigrationPrompt.js +12 -6
- package/lib/sandboxes.d.ts +1 -9
- package/lib/sandboxes.js +0 -21
- package/lib/serverlessLogs.js +50 -44
- package/lib/{cms/devServerProcess.d.ts → theme/cmsDevServerProcess.d.ts} +2 -3
- package/lib/theme/cmsDevServerProcess.js +148 -0
- package/lib/theme/cmsDevServerRunner.d.ts +14 -0
- package/lib/theme/cmsDevServerRunner.js +90 -0
- package/lib/usageTracking.js +8 -5
- package/mcp-server/tools/cms/HsCreateFunctionTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateModuleTool.js +1 -1
- package/mcp-server/tools/cms/HsCreateTemplateTool.js +1 -1
- package/mcp-server/tools/cms/HsFunctionLogsTool.js +1 -1
- package/mcp-server/tools/cms/HsListFunctionsTool.js +1 -1
- package/mcp-server/tools/cms/HsListTool.js +1 -1
- package/mcp-server/tools/cms/__tests__/HsCreateFunctionTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsCreateModuleTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsCreateTemplateTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsFunctionLogsTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsListFunctionsTool.test.js +1 -2
- package/mcp-server/tools/cms/__tests__/HsListTool.test.js +1 -2
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/AddFeatureToProjectTool.js +1 -1
- package/mcp-server/tools/project/CreateProjectTool.d.ts +1 -1
- package/mcp-server/tools/project/CreateProjectTool.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/UploadProjectTools.js +1 -1
- package/mcp-server/tools/project/ValidateProjectTool.js +1 -1
- package/mcp-server/tools/project/__tests__/AddFeatureToProjectTool.test.js +1 -2
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +1 -2
- package/mcp-server/tools/project/__tests__/CreateTestAccountTool.test.js +1 -2
- package/mcp-server/tools/project/__tests__/DeployProjectTool.test.js +1 -2
- package/mcp-server/tools/project/__tests__/UploadProjectTools.test.js +10 -2
- package/mcp-server/tools/project/__tests__/ValidateProjectTool.test.js +2 -2
- package/mcp-server/tools/project/constants.d.ts +1 -1
- package/mcp-server/utils/__tests__/command.test.js +233 -3
- package/mcp-server/utils/__tests__/feedbackTracking.test.js +9 -64
- package/mcp-server/utils/command.d.ts +5 -0
- package/mcp-server/utils/command.js +24 -0
- package/mcp-server/utils/feedbackTracking.js +2 -17
- package/package.json +4 -5
- package/lib/__tests__/sandboxSync.test.d.ts +0 -1
- package/lib/__tests__/sandboxSync.test.js +0 -147
- package/lib/cms/devServerProcess.js +0 -200
- package/lib/sandboxSync.d.ts +0 -4
- package/lib/sandboxSync.js +0 -102
- package/mcp-server/utils/__tests__/project.test.d.ts +0 -1
- package/mcp-server/utils/__tests__/project.test.js +0 -140
- package/mcp-server/utils/project.d.ts +0 -5
- package/mcp-server/utils/project.js +0 -18
|
@@ -6,17 +6,14 @@ import { HUBSPOT_ACCOUNT_TYPES, HUBSPOT_ACCOUNT_TYPE_STRINGS, } from '@hubspot/l
|
|
|
6
6
|
import { commands, lib } from '../../lang/en.js';
|
|
7
7
|
import { EXIT_CODES } from '../../lib/enums/exitCodes.js';
|
|
8
8
|
import { uiFeatureHighlight, uiBetaTag } from '../../lib/ui/index.js';
|
|
9
|
-
import { SANDBOX_TYPE_MAP,
|
|
9
|
+
import { SANDBOX_TYPE_MAP, validateSandboxUsageLimits, } from '../../lib/sandboxes.js';
|
|
10
10
|
import { trackCommandUsage } from '../../lib/usageTracking.js';
|
|
11
11
|
import { sandboxTypePrompt } from '../../lib/prompts/sandboxesPrompt.js';
|
|
12
12
|
import { promptUser } from '../../lib/prompts/promptUtils.js';
|
|
13
|
-
import { syncSandbox } from '../../lib/sandboxSync.js';
|
|
14
13
|
import { logError } from '../../lib/errorHandlers/index.js';
|
|
15
|
-
import {
|
|
14
|
+
import { buildV2Sandbox } from '../../lib/buildAccount.js';
|
|
16
15
|
import { hubspotAccountNamePrompt } from '../../lib/prompts/accountNamePrompt.js';
|
|
17
16
|
import { makeYargsBuilder } from '../../lib/yargsUtils.js';
|
|
18
|
-
import { hasFeature } from '../../lib/hasFeature.js';
|
|
19
|
-
import { FEATURES } from '../../lib/constants.js';
|
|
20
17
|
const command = 'create';
|
|
21
18
|
const describe = uiBetaTag(commands.sandbox.subcommands.create.describe, false);
|
|
22
19
|
async function handler(args) {
|
|
@@ -98,38 +95,14 @@ async function handler(args) {
|
|
|
98
95
|
contactRecordsSyncPromptResult = contactRecordsSyncPrompt;
|
|
99
96
|
}
|
|
100
97
|
}
|
|
101
|
-
// Check if parent portal is ungated for v2 sandboxes
|
|
102
|
-
const isUngatedForV2Cli = await hasFeature(derivedAccountId, FEATURES.SANDBOXES_V2_CLI);
|
|
103
|
-
const isUngatedForV2Sandboxes = await hasFeature(derivedAccountId, FEATURES.SANDBOXES_V2);
|
|
104
|
-
const canCreateV2Sandbox = isUngatedForV2Sandboxes && isUngatedForV2Cli;
|
|
105
98
|
try {
|
|
106
|
-
|
|
107
|
-
if (canCreateV2Sandbox) {
|
|
108
|
-
result = await buildV2Sandbox(sandboxName, accountConfig, sandboxType, contactRecordsSyncPromptResult, env, force);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
result = await buildSandbox(sandboxName, accountConfig, sandboxType, env, force);
|
|
112
|
-
}
|
|
99
|
+
const result = await buildV2Sandbox(sandboxName, accountConfig, sandboxType, contactRecordsSyncPromptResult, env, force);
|
|
113
100
|
const sandboxAccountConfig = getConfigAccountById(result.sandbox.sandboxHubId);
|
|
114
101
|
// Check if sandbox account config exists
|
|
115
102
|
if (!sandboxAccountConfig) {
|
|
116
103
|
uiLogger.error(commands.sandbox.subcommands.create.failure.noSandboxAccountConfig(result.sandbox.sandboxHubId));
|
|
117
104
|
process.exit(EXIT_CODES.ERROR);
|
|
118
105
|
}
|
|
119
|
-
if (result && !canCreateV2Sandbox) {
|
|
120
|
-
// For v1 sandboxes, keep sync here. Once we migrate to v2, this will be handled by BE automatically
|
|
121
|
-
try {
|
|
122
|
-
let availableSyncTasks = await getAvailableSyncTypes(accountConfig, sandboxAccountConfig);
|
|
123
|
-
if (!contactRecordsSyncPromptResult) {
|
|
124
|
-
availableSyncTasks = availableSyncTasks.filter(t => t.type !== SYNC_TYPES.OBJECT_RECORDS);
|
|
125
|
-
}
|
|
126
|
-
await syncSandbox(sandboxAccountConfig, accountConfig, env, availableSyncTasks);
|
|
127
|
-
}
|
|
128
|
-
catch (err) {
|
|
129
|
-
logError(err);
|
|
130
|
-
throw err;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
106
|
const highlightItems = ['accountsUseCommand', 'projectCreateCommand'];
|
|
134
107
|
if (sandboxType === HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX) {
|
|
135
108
|
highlightItems.push('projectDevCommand');
|
|
@@ -12,6 +12,7 @@ import { fileExists } from '../../lib/validation.js';
|
|
|
12
12
|
import { commands } from '../../lang/en.js';
|
|
13
13
|
import { createDeveloperTestAccountConfigPrompt } from '../../lib/prompts/createDeveloperTestAccountConfigPrompt.js';
|
|
14
14
|
import { debugError, logError } from '../../lib/errorHandlers/index.js';
|
|
15
|
+
import { PromptExitError } from '../../lib/errors/PromptExitError.js';
|
|
15
16
|
import SpinniesManager from '../../lib/ui/SpinniesManager.js';
|
|
16
17
|
import { createDeveloperTestAccountV2, saveAccountToConfig, } from '../../lib/buildAccount.js';
|
|
17
18
|
import { ACCOUNT_LEVEL_CHOICES, ACCOUNT_LEVELS } from '../../lib/constants.js';
|
|
@@ -130,6 +131,9 @@ async function handler(args) {
|
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
catch (e) {
|
|
134
|
+
if (e instanceof PromptExitError) {
|
|
135
|
+
process.exit(e.exitCode);
|
|
136
|
+
}
|
|
133
137
|
debugError(e);
|
|
134
138
|
uiLogger.error(commands.testAccount.create.errors.saveAccountToConfigFailure(testAccountConfig.accountName));
|
|
135
139
|
process.exit(EXIT_CODES.ERROR);
|
package/lang/en.d.ts
CHANGED
|
@@ -601,11 +601,6 @@ export declare const commands: {
|
|
|
601
601
|
src: string;
|
|
602
602
|
dest: string;
|
|
603
603
|
};
|
|
604
|
-
warnings: {
|
|
605
|
-
disableInitial: string;
|
|
606
|
-
initialUpload: string;
|
|
607
|
-
notUploaded: (path: string) => string;
|
|
608
|
-
};
|
|
609
604
|
};
|
|
610
605
|
fetch: {
|
|
611
606
|
describe: string;
|
|
@@ -1261,7 +1256,6 @@ export declare const commands: {
|
|
|
1261
1256
|
};
|
|
1262
1257
|
success: (derivedTargets: string[]) => string;
|
|
1263
1258
|
errors: {
|
|
1264
|
-
needsMcpAccess: (accountId?: number) => string;
|
|
1265
1259
|
errorParsingJsonFIle: (filename: string, errorMessage: string) => string;
|
|
1266
1260
|
};
|
|
1267
1261
|
spinners: {
|
|
@@ -1295,6 +1289,8 @@ export declare const commands: {
|
|
|
1295
1289
|
prompts: {
|
|
1296
1290
|
targets: string;
|
|
1297
1291
|
targetsRequired: string;
|
|
1292
|
+
standaloneMode: string;
|
|
1293
|
+
cliVersion: string;
|
|
1298
1294
|
};
|
|
1299
1295
|
};
|
|
1300
1296
|
start: {
|
|
@@ -3478,6 +3474,7 @@ export declare const lib: {
|
|
|
3478
3474
|
invalidOauthClientSecretCopy: string;
|
|
3479
3475
|
invalidPersonalAccessKey: string;
|
|
3480
3476
|
invalidPersonalAccessKeyCopy: string;
|
|
3477
|
+
authCancelled: string;
|
|
3481
3478
|
};
|
|
3482
3479
|
};
|
|
3483
3480
|
createTemplatePrompt: {
|
|
@@ -3981,4 +3978,14 @@ export declare const lib: {
|
|
|
3981
3978
|
copyingProjectFilesFailed: string;
|
|
3982
3979
|
};
|
|
3983
3980
|
};
|
|
3981
|
+
theme: {
|
|
3982
|
+
cmsDevServerProcess: {
|
|
3983
|
+
installStarted: (targetVersion: string) => string;
|
|
3984
|
+
installSucceeded: string;
|
|
3985
|
+
installFailed: string;
|
|
3986
|
+
serverStartError: (error: Error) => string;
|
|
3987
|
+
serverExit: (code: number) => string;
|
|
3988
|
+
serverKill: (signal: NodeJS.Signals) => string;
|
|
3989
|
+
};
|
|
3990
|
+
};
|
|
3984
3991
|
};
|
package/lang/en.js
CHANGED
|
@@ -609,11 +609,6 @@ export const commands = {
|
|
|
609
609
|
src: 'Path to the local directory your files are in, relative to your current working directory',
|
|
610
610
|
dest: 'Path in HubSpot Design Tools. Can be a net new path',
|
|
611
611
|
},
|
|
612
|
-
warnings: {
|
|
613
|
-
disableInitial: `Passing the "${chalk.bold('--disable-initial')}" option is no longer necessary. Running "${uiCommandReference('hs watch')}" no longer uploads the watched directory by default.`,
|
|
614
|
-
initialUpload: `To upload the directory run "${uiCommandReference('hs upload')}" beforehand or add the "${chalk.bold('--initial-upload')}" option when running "${uiCommandReference('hs watch')}".`,
|
|
615
|
-
notUploaded: (path) => `The "${uiCommandReference('hs watch')}" command no longer uploads the watched directory when started. The directory "${path}" was not uploaded.`,
|
|
616
|
-
},
|
|
617
612
|
},
|
|
618
613
|
fetch: {
|
|
619
614
|
describe: 'Fetch a file, directory or module from HubSpot and write to a path on your computer.',
|
|
@@ -1271,7 +1266,6 @@ export const commands = {
|
|
|
1271
1266
|
},
|
|
1272
1267
|
success: (derivedTargets) => `You can now use the HubSpot CLI MCP Server in ${derivedTargets.join(', ')}. ${chalk.bold('You may need to restart these tools to apply the changes')}.`,
|
|
1273
1268
|
errors: {
|
|
1274
|
-
needsMcpAccess: (accountId) => `You must opt in to the developer MCP beta to use this feature on ${uiAccountDescription(accountId)}. Try again with a different account or ${uiLink('join the beta now', getProductUpdatesUrl('239890', accountId))}`,
|
|
1275
1269
|
errorParsingJsonFIle: (filename, errorMessage) => `Unable to update ${chalk.bold(filename)} due to invalid JSON: ${errorMessage}`,
|
|
1276
1270
|
},
|
|
1277
1271
|
spinners: {
|
|
@@ -1311,6 +1305,8 @@ export const commands = {
|
|
|
1311
1305
|
prompts: {
|
|
1312
1306
|
targets: '[--client] Which tools would you like to add the HubSpot CLI MCP server to?',
|
|
1313
1307
|
targetsRequired: 'Must choose at least one app to configure.',
|
|
1308
|
+
standaloneMode: 'Do you want to run in standalone mode? (This will use npx @hubspot/cli instead of the installed hs command)',
|
|
1309
|
+
cliVersion: 'Specify a CLI version to pin (leave blank for latest):',
|
|
1314
1310
|
},
|
|
1315
1311
|
},
|
|
1316
1312
|
start: {
|
|
@@ -3501,6 +3497,7 @@ export const lib = {
|
|
|
3501
3497
|
invalidOauthClientSecretCopy: 'Please copy the actual OAuth2 client secret rather than the asterisks that mask it.',
|
|
3502
3498
|
invalidPersonalAccessKey: 'You did not enter a valid access key. Please try again.',
|
|
3503
3499
|
invalidPersonalAccessKeyCopy: 'Please copy the actual access key rather than the bullets that mask it.',
|
|
3500
|
+
authCancelled: 'Authentication cancelled.',
|
|
3504
3501
|
},
|
|
3505
3502
|
},
|
|
3506
3503
|
createTemplatePrompt: {
|
|
@@ -4004,4 +4001,14 @@ export const lib = {
|
|
|
4004
4001
|
copyingProjectFilesFailed: 'Unable to copy migrated project files',
|
|
4005
4002
|
},
|
|
4006
4003
|
},
|
|
4004
|
+
theme: {
|
|
4005
|
+
cmsDevServerProcess: {
|
|
4006
|
+
installStarted: (targetVersion) => `Installing cms-dev-server ${targetVersion}...`,
|
|
4007
|
+
installSucceeded: 'cms-dev-server setup complete',
|
|
4008
|
+
installFailed: 'Failed to install cms-dev-server',
|
|
4009
|
+
serverStartError: (error) => `Failed to start dev server: ${error}`,
|
|
4010
|
+
serverExit: (code) => `Dev server exited with code ${code}`,
|
|
4011
|
+
serverKill: (signal) => `Dev server killed with signal ${signal}`,
|
|
4012
|
+
},
|
|
4013
|
+
},
|
|
4007
4014
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getAccessToken, updateConfigWithAccessToken, } from '@hubspot/local-dev-lib/personalAccessKey';
|
|
2
2
|
import { getConfigAccountIfExists, updateConfigAccount, } from '@hubspot/local-dev-lib/config';
|
|
3
3
|
import { createDeveloperTestAccount, fetchDeveloperTestAccountGateSyncStatus, generateDeveloperTestAccountPersonalAccessKey, } from '@hubspot/local-dev-lib/api/developerTestAccounts';
|
|
4
|
-
import {
|
|
4
|
+
import { createV2Sandbox, getSandboxPersonalAccessKey, } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
5
5
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
6
6
|
import { personalAccessKeyPrompt } from '../prompts/personalAccessKeyPrompt.js';
|
|
7
7
|
import { cliAccountNamePrompt } from '../prompts/accountNamePrompt.js';
|
|
@@ -32,7 +32,6 @@ const mockedCliAccountNamePrompt = cliAccountNamePrompt;
|
|
|
32
32
|
const mockedCreateDeveloperTestAccount = createDeveloperTestAccount;
|
|
33
33
|
const mockedFetchDeveloperTestAccountGateSyncStatus = fetchDeveloperTestAccountGateSyncStatus;
|
|
34
34
|
const mockedGenerateDeveloperTestAccountPersonalAccessKey = generateDeveloperTestAccountPersonalAccessKey;
|
|
35
|
-
const mockedCreateSandbox = createSandbox;
|
|
36
35
|
const mockedCreateV2Sandbox = createV2Sandbox;
|
|
37
36
|
const mockedGetPersonalAccessKey = getSandboxPersonalAccessKey;
|
|
38
37
|
const mockedPoll = poll;
|
|
@@ -162,56 +161,6 @@ describe('lib/buildAccount', () => {
|
|
|
162
161
|
await expect(buildAccount.buildDeveloperTestAccount(mockDeveloperTestAccount.accountName, mockParentAccountConfig, mockParentAccountConfig.env, 10)).rejects.toThrow();
|
|
163
162
|
});
|
|
164
163
|
});
|
|
165
|
-
describe('buildSandbox()', () => {
|
|
166
|
-
const mockParentAccountConfig = {
|
|
167
|
-
name: 'Prod account',
|
|
168
|
-
accountId: 123456,
|
|
169
|
-
accountType: HUBSPOT_ACCOUNT_TYPES.STANDARD,
|
|
170
|
-
env: 'prod',
|
|
171
|
-
};
|
|
172
|
-
const mockSandbox = {
|
|
173
|
-
sandboxHubId: 56789,
|
|
174
|
-
parentHubId: 123456,
|
|
175
|
-
createdAt: '2025-01-01',
|
|
176
|
-
type: 'STANDARD',
|
|
177
|
-
version: 'V1',
|
|
178
|
-
archived: false,
|
|
179
|
-
name: 'Test Sandbox',
|
|
180
|
-
domain: 'test-sandbox.hubspot.com',
|
|
181
|
-
createdByUser: {
|
|
182
|
-
id: 123456,
|
|
183
|
-
email: 'test@test.com',
|
|
184
|
-
firstName: 'Test',
|
|
185
|
-
lastName: 'User',
|
|
186
|
-
},
|
|
187
|
-
};
|
|
188
|
-
beforeEach(() => {
|
|
189
|
-
vi.spyOn(buildAccount, 'saveAccountToConfig').mockResolvedValue(mockParentAccountConfig.name);
|
|
190
|
-
mockedCreateSandbox.mockResolvedValue({
|
|
191
|
-
data: { sandbox: mockSandbox, personalAccessKey: 'test-key' },
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
it('should create a standard sandbox successfully', async () => {
|
|
195
|
-
const result = await buildAccount.buildSandbox(mockSandbox.name, mockParentAccountConfig, HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX, mockParentAccountConfig.env, false);
|
|
196
|
-
expect(result).toEqual({
|
|
197
|
-
name: mockSandbox.name,
|
|
198
|
-
personalAccessKey: 'test-key',
|
|
199
|
-
sandbox: mockSandbox,
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
it('should create a development sandbox successfully', async () => {
|
|
203
|
-
const result = await buildAccount.buildSandbox(mockSandbox.name, mockParentAccountConfig, HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX, mockParentAccountConfig.env);
|
|
204
|
-
expect(result).toEqual({
|
|
205
|
-
name: mockSandbox.name,
|
|
206
|
-
personalAccessKey: 'test-key',
|
|
207
|
-
sandbox: mockSandbox,
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
it('should handle API errors when creating sandbox', async () => {
|
|
211
|
-
mockedCreateSandbox.mockRejectedValue(new Error('test-error'));
|
|
212
|
-
await expect(buildAccount.buildSandbox(mockSandbox.name, mockParentAccountConfig, HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX, mockParentAccountConfig.env, false)).rejects.toThrow();
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
164
|
describe('buildV2Sandbox()', () => {
|
|
216
165
|
const mockParentAccountConfig = {
|
|
217
166
|
name: 'Prod account',
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { uiLogger } from '../ui/logger.js';
|
|
2
2
|
import { getSandboxUsageLimits } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
3
|
-
import { fetchTypes } from '@hubspot/local-dev-lib/api/sandboxSync';
|
|
4
3
|
import { getAllConfigAccounts, getConfigAccountIfExists, } from '@hubspot/local-dev-lib/config';
|
|
5
4
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
6
5
|
import { mockHubSpotHttpError } from '../testUtils.js';
|
|
7
|
-
import { getSandboxTypeAsString, getHasSandboxesByType,
|
|
6
|
+
import { getSandboxTypeAsString, getHasSandboxesByType, validateSandboxUsageLimits, handleSandboxCreateError, } from '../sandboxes.js';
|
|
8
7
|
import { isMissingScopeError, isSpecifiedError, } from '@hubspot/local-dev-lib/errors/index';
|
|
9
8
|
vi.mock('@hubspot/local-dev-lib/api/sandboxHubs');
|
|
10
9
|
vi.mock('@hubspot/local-dev-lib/api/sandboxSync');
|
|
@@ -12,7 +11,6 @@ vi.mock('@hubspot/local-dev-lib/config');
|
|
|
12
11
|
vi.mock('@hubspot/local-dev-lib/errors/index');
|
|
13
12
|
const mockedGetConfigAccountIfExists = getConfigAccountIfExists;
|
|
14
13
|
const mockedGetSandboxUsageLimits = getSandboxUsageLimits;
|
|
15
|
-
const mockedFetchTypes = fetchTypes;
|
|
16
14
|
const mockedGetAllConfigAccounts = getAllConfigAccounts;
|
|
17
15
|
const mockedUiLogger = uiLogger;
|
|
18
16
|
const mockedIsMissingScopeError = isMissingScopeError;
|
|
@@ -53,32 +51,6 @@ describe('lib/sandboxes', () => {
|
|
|
53
51
|
expect(getHasSandboxesByType(mockParentAccount, HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX)).toBe(false);
|
|
54
52
|
});
|
|
55
53
|
});
|
|
56
|
-
describe('getAvailableSyncTypes()', () => {
|
|
57
|
-
const mockParentAccount = {
|
|
58
|
-
name: 'Parent Account',
|
|
59
|
-
accountId: 123,
|
|
60
|
-
env: 'qa',
|
|
61
|
-
};
|
|
62
|
-
const mockChildAccount = {
|
|
63
|
-
...mockParentAccount,
|
|
64
|
-
accountId: 456,
|
|
65
|
-
};
|
|
66
|
-
it('returns available sync types when fetch is successful', async () => {
|
|
67
|
-
const mockSyncTypes = [{ name: 'type1' }, { name: 'type2' }];
|
|
68
|
-
mockedGetConfigAccountIfExists
|
|
69
|
-
.mockReturnValue(mockParentAccount.accountId)
|
|
70
|
-
.mockReturnValue(mockChildAccount.accountId);
|
|
71
|
-
mockedFetchTypes.mockResolvedValue({
|
|
72
|
-
data: { results: mockSyncTypes },
|
|
73
|
-
});
|
|
74
|
-
const result = await getAvailableSyncTypes(mockParentAccount, mockChildAccount);
|
|
75
|
-
expect(result).toEqual([{ type: 'type1' }, { type: 'type2' }]);
|
|
76
|
-
});
|
|
77
|
-
it('throws error when sync types fetch fails', async () => {
|
|
78
|
-
mockedFetchTypes.mockResolvedValue({ data: { results: null } });
|
|
79
|
-
await expect(getAvailableSyncTypes(mockParentAccount, mockChildAccount)).rejects.toThrow(/Unable to fetch available sandbox sync types/);
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
54
|
describe('validateSandboxUsageLimits()', () => {
|
|
83
55
|
const mockAccount = {
|
|
84
56
|
name: 'Test Account',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import mockStdIn from 'mock-stdin';
|
|
2
1
|
import { outputLogs } from '../ui/serverlessFunctionLogs.js';
|
|
3
2
|
import { tailLogs } from '../serverlessLogs.js';
|
|
3
|
+
import { handleKeypress } from '../process.js';
|
|
4
4
|
vi.mock('../ui/serverlessFunctionLogs');
|
|
5
5
|
vi.mock('../ui/SpinniesManager', () => ({
|
|
6
6
|
default: {
|
|
@@ -12,82 +12,87 @@ vi.mock('../ui/SpinniesManager', () => ({
|
|
|
12
12
|
stopAll: vi.fn(),
|
|
13
13
|
},
|
|
14
14
|
}));
|
|
15
|
+
vi.mock('../process');
|
|
15
16
|
vi.useFakeTimers();
|
|
16
17
|
const ACCOUNT_ID = 123;
|
|
18
|
+
function terminateTailLogs() {
|
|
19
|
+
const keypressCallback = vi.mocked(handleKeypress).mock.calls[0][0];
|
|
20
|
+
keypressCallback({ name: 'q' });
|
|
21
|
+
}
|
|
17
22
|
describe('lib/serverlessLogs', () => {
|
|
18
23
|
describe('tailLogs()', () => {
|
|
19
|
-
let stdinMock;
|
|
20
|
-
beforeEach(() => {
|
|
21
|
-
// @ts-ignore - we don't need to mock the entire process object
|
|
22
|
-
vi.spyOn(process, 'exit').mockImplementation(() => { });
|
|
23
|
-
stdinMock = mockStdIn.stdin();
|
|
24
|
-
});
|
|
25
24
|
afterEach(() => {
|
|
26
25
|
vi.clearAllTimers();
|
|
27
|
-
|
|
26
|
+
vi.clearAllMocks();
|
|
28
27
|
});
|
|
29
28
|
it('calls tailCall() to get the next results', async () => {
|
|
30
29
|
const compact = false;
|
|
31
|
-
const fetchLatest = vi.fn(() => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
next: {
|
|
55
|
-
after: 'somehash',
|
|
56
|
-
},
|
|
30
|
+
const fetchLatest = vi.fn(() => Promise.resolve({
|
|
31
|
+
data: {
|
|
32
|
+
id: '1234',
|
|
33
|
+
executionTime: 510,
|
|
34
|
+
log: 'Log message',
|
|
35
|
+
error: { message: '', type: '', stackTrace: [] },
|
|
36
|
+
status: 'SUCCESS',
|
|
37
|
+
createdAt: 1620232011451,
|
|
38
|
+
memory: '70/128 MB',
|
|
39
|
+
duration: '53.40 ms',
|
|
40
|
+
},
|
|
41
|
+
status: 200,
|
|
42
|
+
statusText: 'OK',
|
|
43
|
+
headers: {},
|
|
44
|
+
// eslint-disable-next-line
|
|
45
|
+
config: { headers: {} },
|
|
46
|
+
}));
|
|
47
|
+
const tailCall = vi.fn(() => Promise.resolve({
|
|
48
|
+
data: {
|
|
49
|
+
results: [],
|
|
50
|
+
paging: {
|
|
51
|
+
next: {
|
|
52
|
+
after: 'somehash',
|
|
57
53
|
},
|
|
58
54
|
},
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
55
|
+
},
|
|
56
|
+
status: 200,
|
|
57
|
+
statusText: 'OK',
|
|
58
|
+
headers: {},
|
|
59
|
+
// eslint-disable-next-line
|
|
60
|
+
config: { headers: {} },
|
|
61
|
+
}));
|
|
65
62
|
// @ts-ignore - headers is not used in the actual function and does not need to be mocked
|
|
66
|
-
|
|
67
|
-
vi.
|
|
63
|
+
const tailPromise = tailLogs(ACCOUNT_ID, 'name', fetchLatest, tailCall, compact);
|
|
64
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
68
65
|
expect(fetchLatest).toHaveBeenCalled();
|
|
66
|
+
expect(tailCall).toHaveBeenCalledTimes(1);
|
|
67
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
69
68
|
expect(tailCall).toHaveBeenCalledTimes(2);
|
|
69
|
+
terminateTailLogs();
|
|
70
|
+
await tailPromise;
|
|
70
71
|
});
|
|
71
72
|
it('outputs results', async () => {
|
|
72
73
|
const compact = false;
|
|
73
|
-
const fetchLatest = vi.fn(() => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
duration: '53.40 ms',
|
|
74
|
+
const fetchLatest = vi.fn(() => Promise.resolve({
|
|
75
|
+
data: {
|
|
76
|
+
id: '1234',
|
|
77
|
+
executionTime: 510,
|
|
78
|
+
log: 'Log message',
|
|
79
|
+
error: {
|
|
80
|
+
message: '',
|
|
81
|
+
type: '',
|
|
82
|
+
stackTrace: [],
|
|
83
|
+
statusCode: null,
|
|
84
84
|
},
|
|
85
|
-
status:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
|
|
85
|
+
status: 'SUCCESS',
|
|
86
|
+
createdAt: 1620232011451,
|
|
87
|
+
memory: '70/128 MB',
|
|
88
|
+
duration: '53.40 ms',
|
|
89
|
+
},
|
|
90
|
+
status: 200,
|
|
91
|
+
statusText: 'OK',
|
|
92
|
+
headers: {},
|
|
93
|
+
// eslint-disable-next-line
|
|
94
|
+
config: { headers: {} },
|
|
95
|
+
}));
|
|
91
96
|
const latestLogResponse = {
|
|
92
97
|
results: [
|
|
93
98
|
{
|
|
@@ -117,12 +122,23 @@ describe('lib/serverlessLogs', () => {
|
|
|
117
122
|
},
|
|
118
123
|
},
|
|
119
124
|
};
|
|
120
|
-
const tailCall = vi.fn(() => Promise.resolve({
|
|
125
|
+
const tailCall = vi.fn(() => Promise.resolve({
|
|
126
|
+
data: latestLogResponse,
|
|
127
|
+
status: 200,
|
|
128
|
+
statusText: 'OK',
|
|
129
|
+
headers: {},
|
|
130
|
+
// eslint-disable-next-line
|
|
131
|
+
config: { headers: {} },
|
|
132
|
+
}));
|
|
121
133
|
// @ts-ignore - headers is not used in the actual function and does not need to be mocked
|
|
122
|
-
|
|
123
|
-
vi.
|
|
134
|
+
const tailPromise = tailLogs(ACCOUNT_ID, 'name', fetchLatest, tailCall, compact);
|
|
135
|
+
await vi.advanceTimersByTimeAsync(0);
|
|
124
136
|
expect(outputLogs).toHaveBeenCalledWith(latestLogResponse, expect.objectContaining({ compact }));
|
|
137
|
+
expect(tailCall).toHaveBeenCalledTimes(1);
|
|
138
|
+
await vi.advanceTimersByTimeAsync(5000);
|
|
125
139
|
expect(tailCall).toHaveBeenCalledTimes(2);
|
|
140
|
+
terminateTailLogs();
|
|
141
|
+
await tailPromise;
|
|
126
142
|
});
|
|
127
143
|
it('handles no logs', async () => {
|
|
128
144
|
const compact = false;
|
|
@@ -141,8 +157,7 @@ describe('lib/serverlessLogs', () => {
|
|
|
141
157
|
statusCode: 404,
|
|
142
158
|
}));
|
|
143
159
|
await tailLogs(ACCOUNT_ID, 'name', fetchLatest, tailCall, compact);
|
|
144
|
-
|
|
145
|
-
expect(tailCall).toHaveBeenCalledTimes(2);
|
|
160
|
+
expect(tailCall).toHaveBeenCalledTimes(1);
|
|
146
161
|
});
|
|
147
162
|
});
|
|
148
163
|
});
|
package/lib/accountAuth.js
CHANGED
|
@@ -3,6 +3,7 @@ import { getAccessToken, updateConfigWithAccessToken, } from '@hubspot/local-dev
|
|
|
3
3
|
import { toKebabCase } from '@hubspot/local-dev-lib/text';
|
|
4
4
|
import { handleMerge, handleMigration } from './configMigrate.js';
|
|
5
5
|
import { debugError, logError } from './errorHandlers/index.js';
|
|
6
|
+
import { PromptExitError } from './errors/PromptExitError.js';
|
|
6
7
|
import { personalAccessKeyPrompt } from './prompts/personalAccessKeyPrompt.js';
|
|
7
8
|
import { cliAccountNamePrompt } from './prompts/accountNamePrompt.js';
|
|
8
9
|
import { setAsDefaultAccountPrompt } from './prompts/setAsDefaultAccountPrompt.js';
|
|
@@ -36,6 +37,9 @@ async function updateConfigWithNewAccount(env, configAlreadyExists, providedPers
|
|
|
36
37
|
return updatedConfig;
|
|
37
38
|
}
|
|
38
39
|
catch (e) {
|
|
40
|
+
if (e instanceof PromptExitError) {
|
|
41
|
+
throw e;
|
|
42
|
+
}
|
|
39
43
|
debugError(e);
|
|
40
44
|
return null;
|
|
41
45
|
}
|
package/lib/buildAccount.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DeveloperTestAccountConfig } from '@hubspot/local-dev-lib/types/developerTestAccounts';
|
|
2
2
|
import { Environment } from '@hubspot/local-dev-lib/types/Accounts';
|
|
3
3
|
import { HubSpotConfigAccount } from '@hubspot/local-dev-lib/types/Accounts';
|
|
4
|
-
import {
|
|
4
|
+
import { V2Sandbox } from '@hubspot/local-dev-lib/types/Sandbox';
|
|
5
5
|
import { SandboxAccountType } from '../types/Sandboxes.js';
|
|
6
6
|
export declare function saveAccountToConfig(accountId: number | undefined, accountName: string, env: Environment, personalAccessKey?: string, force?: boolean): Promise<string>;
|
|
7
7
|
export declare function createDeveloperTestAccountV2(parentAccountId: number, testAccountConfig: DeveloperTestAccountConfig): Promise<{
|
|
@@ -10,11 +10,6 @@ export declare function createDeveloperTestAccountV2(parentAccountId: number, te
|
|
|
10
10
|
personalAccessKey?: string;
|
|
11
11
|
}>;
|
|
12
12
|
export declare function buildDeveloperTestAccount(testAccountName: string, parentAccountConfig: HubSpotConfigAccount, env: Environment, portalLimit: number, useV2?: boolean): Promise<number>;
|
|
13
|
-
type SandboxAccount = SandboxResponse & {
|
|
14
|
-
name: string;
|
|
15
|
-
};
|
|
16
|
-
export declare function buildSandbox(sandboxName: string, parentAccountConfig: HubSpotConfigAccount, sandboxType: SandboxAccountType, env: Environment, force?: boolean): Promise<SandboxAccount>;
|
|
17
13
|
export declare function buildV2Sandbox(sandboxName: string, parentAccountConfig: HubSpotConfigAccount, sandboxType: SandboxAccountType, syncObjectRecords: boolean, env: Environment, force?: boolean): Promise<{
|
|
18
14
|
sandbox: V2Sandbox;
|
|
19
15
|
}>;
|
|
20
|
-
export {};
|
package/lib/buildAccount.js
CHANGED
|
@@ -3,13 +3,14 @@ import { getConfigAccountIfExists, updateConfigAccount, } from '@hubspot/local-d
|
|
|
3
3
|
import { uiLogger } from './ui/logger.js';
|
|
4
4
|
import { createDeveloperTestAccount, fetchDeveloperTestAccountGateSyncStatus, generateDeveloperTestAccountPersonalAccessKey, } from '@hubspot/local-dev-lib/api/developerTestAccounts';
|
|
5
5
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
6
|
-
import {
|
|
6
|
+
import { createV2Sandbox, getSandboxPersonalAccessKey, } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
7
|
+
import { PromptExitError } from './errors/PromptExitError.js';
|
|
7
8
|
import { personalAccessKeyPrompt } from './prompts/personalAccessKeyPrompt.js';
|
|
8
9
|
import { createDeveloperTestAccountConfigPrompt } from './prompts/createDeveloperTestAccountConfigPrompt.js';
|
|
9
10
|
import { cliAccountNamePrompt } from './prompts/accountNamePrompt.js';
|
|
10
11
|
import SpinniesManager from './ui/SpinniesManager.js';
|
|
11
12
|
import { debugError, logError } from './errorHandlers/index.js';
|
|
12
|
-
import {
|
|
13
|
+
import { SANDBOX_TYPE_MAP_V2, handleSandboxCreateError } from './sandboxes.js';
|
|
13
14
|
import { handleDeveloperTestAccountCreateError } from './developerTestAccounts.js';
|
|
14
15
|
import { lib } from '../lang/en.js';
|
|
15
16
|
import { poll } from './polling.js';
|
|
@@ -127,51 +128,14 @@ export async function buildDeveloperTestAccount(testAccountName, parentAccountCo
|
|
|
127
128
|
await saveAccountToConfig(developerTestAccountId, testAccountName, env, developerTestAccountPersonalAccessKey);
|
|
128
129
|
}
|
|
129
130
|
catch (err) {
|
|
131
|
+
if (err instanceof PromptExitError) {
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
130
134
|
logError(err);
|
|
131
135
|
throw err;
|
|
132
136
|
}
|
|
133
137
|
return developerTestAccountId;
|
|
134
138
|
}
|
|
135
|
-
export async function buildSandbox(sandboxName, parentAccountConfig, sandboxType, env, force = false) {
|
|
136
|
-
const sandboxTypeKey = sandboxType === HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX
|
|
137
|
-
? 'standard'
|
|
138
|
-
: 'developer';
|
|
139
|
-
const parentAccountId = parentAccountConfig.accountId;
|
|
140
|
-
if (!parentAccountId) {
|
|
141
|
-
throw new Error(lib.sandbox.create[sandboxTypeKey].loading.fail(''));
|
|
142
|
-
}
|
|
143
|
-
SpinniesManager.init({
|
|
144
|
-
succeedColor: 'white',
|
|
145
|
-
});
|
|
146
|
-
uiLogger.log('');
|
|
147
|
-
SpinniesManager.add('buildSandbox', {
|
|
148
|
-
text: lib.sandbox.create[sandboxTypeKey].loading.add(sandboxName),
|
|
149
|
-
});
|
|
150
|
-
let sandbox;
|
|
151
|
-
try {
|
|
152
|
-
const sandboxApiType = SANDBOX_API_TYPE_MAP[sandboxType];
|
|
153
|
-
const { data } = await createSandbox(parentAccountId, sandboxName, sandboxApiType);
|
|
154
|
-
sandbox = { name: sandboxName, ...data };
|
|
155
|
-
SpinniesManager.succeed('buildSandbox', {
|
|
156
|
-
text: lib.sandbox.create[sandboxTypeKey].loading.succeed(sandboxName, sandbox.sandbox.sandboxHubId.toString()),
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
catch (e) {
|
|
160
|
-
debugError(e);
|
|
161
|
-
SpinniesManager.fail('buildSandbox', {
|
|
162
|
-
text: lib.sandbox.create[sandboxTypeKey].loading.fail(sandboxName),
|
|
163
|
-
});
|
|
164
|
-
handleSandboxCreateError(e, env, sandboxName, parentAccountId);
|
|
165
|
-
}
|
|
166
|
-
try {
|
|
167
|
-
await saveAccountToConfig(sandbox.sandbox.sandboxHubId, sandboxName, env, sandbox.personalAccessKey, force);
|
|
168
|
-
}
|
|
169
|
-
catch (err) {
|
|
170
|
-
logError(err);
|
|
171
|
-
throw err;
|
|
172
|
-
}
|
|
173
|
-
return sandbox;
|
|
174
|
-
}
|
|
175
139
|
export async function buildV2Sandbox(sandboxName, parentAccountConfig, sandboxType, syncObjectRecords, env, force = false) {
|
|
176
140
|
const sandboxTypeKey = sandboxType === HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX
|
|
177
141
|
? 'standard'
|
|
@@ -210,6 +174,9 @@ export async function buildV2Sandbox(sandboxName, parentAccountConfig, sandboxTy
|
|
|
210
174
|
await saveAccountToConfig(sandbox.sandboxHubId, sandboxName, env, pak, force);
|
|
211
175
|
}
|
|
212
176
|
catch (err) {
|
|
177
|
+
if (err instanceof PromptExitError) {
|
|
178
|
+
throw err;
|
|
179
|
+
}
|
|
213
180
|
logError(err);
|
|
214
181
|
throw err;
|
|
215
182
|
}
|
package/lib/constants.d.ts
CHANGED
|
@@ -77,11 +77,8 @@ export declare const APP_AUTH_TYPES: {
|
|
|
77
77
|
};
|
|
78
78
|
export declare const FEATURES: {
|
|
79
79
|
readonly UNIFIED_APPS: "Developers:UnifiedApps:PrivateBeta";
|
|
80
|
-
readonly SANDBOXES_V2: "sandboxes:v2:enabled";
|
|
81
|
-
readonly SANDBOXES_V2_CLI: "sandboxes:v2:cliEnabled";
|
|
82
80
|
readonly APP_EVENTS: "Developers:UnifiedApps:AppEventsAccess";
|
|
83
81
|
readonly APPS_HOME: "UIE:AppHome";
|
|
84
|
-
readonly MCP_ACCESS: "Developers:CLIMCPAccess";
|
|
85
82
|
readonly THEME_MIGRATION_2025_2: "Developers:ProjectThemeMigrations:2025.2";
|
|
86
83
|
readonly AGENT_TOOLS: "ThirdPartyAgentTools";
|
|
87
84
|
};
|
|
@@ -145,3 +142,4 @@ export declare const ACCOUNT_LEVELS: {
|
|
|
145
142
|
readonly ENTERPRISE: "ENTERPRISE";
|
|
146
143
|
};
|
|
147
144
|
export declare const ACCOUNT_LEVEL_CHOICES: readonly ["FREE", "STARTER", "PROFESSIONAL", "ENTERPRISE"];
|
|
145
|
+
export declare const FEEDBACK_URL = "https://developers.hubspot.com/feedback";
|