@hubspot/cli 8.0.10-experimental.4 → 8.0.10-experimental.5
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/api/migrate.js +2 -2
- package/commands/account/auth.js +15 -5
- package/commands/account/use.js +14 -4
- package/commands/app/__tests__/migrate.test.js +2 -2
- package/commands/app/migrate.js +3 -3
- package/commands/auth.js +10 -6
- 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/project/__tests__/create.test.js +2 -2
- package/commands/project/__tests__/migrate.test.js +1 -1
- package/commands/project/create.js +3 -3
- package/commands/project/dev/index.js +29 -19
- package/commands/project/download.js +5 -1
- package/commands/project/migrate.js +1 -1
- 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 +1 -1
- package/lang/en.js +1 -1
- package/lib/__tests__/buildAccount.test.js +1 -52
- package/lib/__tests__/sandboxes.test.js +1 -29
- package/lib/accountAuth.js +4 -0
- package/lib/app/__tests__/migrate.test.js +1 -1
- package/lib/app/migrate.js +1 -1
- package/lib/buildAccount.d.ts +1 -6
- package/lib/buildAccount.js +9 -42
- package/lib/constants.d.ts +0 -2
- package/lib/constants.js +0 -2
- package/lib/errors/PromptExitError.d.ts +4 -0
- package/lib/errors/PromptExitError.js +8 -0
- package/lib/projects/__tests__/components.test.js +14 -0
- package/lib/projects/components.js +12 -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/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/theme/__tests__/migrate.test.js +1 -5
- package/mcp-server/tools/project/AddFeatureToProjectTool.d.ts +1 -0
- package/mcp-server/tools/project/CreateProjectTool.d.ts +1 -0
- package/mcp-server/tools/project/CreateProjectTool.js +2 -1
- package/mcp-server/tools/project/__tests__/CreateProjectTool.test.js +0 -1
- package/mcp-server/tools/project/constants.d.ts +1 -0
- package/mcp-server/tools/project/constants.js +2 -1
- package/package.json +1 -1
- package/lib/__tests__/sandboxSync.test.d.ts +0 -1
- package/lib/__tests__/sandboxSync.test.js +0 -147
- package/lib/sandboxSync.d.ts +0 -4
- package/lib/sandboxSync.js +0 -102
package/lib/sandboxes.d.ts
CHANGED
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { AccountType, HubSpotConfigAccount } from '@hubspot/local-dev-lib/types/Accounts';
|
|
2
2
|
import { Environment } from '@hubspot/local-dev-lib/types/Accounts';
|
|
3
|
-
import {
|
|
4
|
-
export declare const SYNC_TYPES: {
|
|
5
|
-
readonly OBJECT_RECORDS: "object-records";
|
|
6
|
-
};
|
|
3
|
+
import { SandboxAccountType } from '../types/Sandboxes.js';
|
|
7
4
|
export declare const SANDBOX_TYPE_MAP: {
|
|
8
5
|
[key: string]: SandboxAccountType;
|
|
9
6
|
};
|
|
10
|
-
export declare const SANDBOX_API_TYPE_MAP: {
|
|
11
|
-
readonly STANDARD_SANDBOX: 1;
|
|
12
|
-
readonly DEVELOPMENT_SANDBOX: 2;
|
|
13
|
-
};
|
|
14
7
|
export declare const SANDBOX_TYPE_MAP_V2: {
|
|
15
8
|
readonly STANDARD_SANDBOX: "STANDARD";
|
|
16
9
|
readonly DEVELOPMENT_SANDBOX: "DEVELOPER";
|
|
17
10
|
};
|
|
18
11
|
export declare function getSandboxTypeAsString(accountType?: AccountType): string;
|
|
19
12
|
export declare function getHasSandboxesByType(parentAccountConfig: HubSpotConfigAccount, type: AccountType): boolean;
|
|
20
|
-
export declare function getAvailableSyncTypes(parentAccountConfig: HubSpotConfigAccount, config: HubSpotConfigAccount): Promise<Array<SandboxSyncTask>>;
|
|
21
13
|
export declare function validateSandboxUsageLimits(accountConfig: HubSpotConfigAccount, sandboxType: AccountType, env: Environment): Promise<void>;
|
|
22
14
|
export declare function handleSandboxCreateError(err: unknown, env: Environment, name: string, accountId: number): never;
|
package/lib/sandboxes.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { getSandboxUsageLimits } from '@hubspot/local-dev-lib/api/sandboxHubs';
|
|
2
|
-
import { fetchTypes } from '@hubspot/local-dev-lib/api/sandboxSync';
|
|
3
2
|
import { getAllConfigAccounts } from '@hubspot/local-dev-lib/config';
|
|
4
3
|
import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
|
|
5
4
|
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
@@ -8,19 +7,12 @@ import { uiLogger } from './ui/logger.js';
|
|
|
8
7
|
import { lib } from '../lang/en.js';
|
|
9
8
|
import { logError } from './errorHandlers/index.js';
|
|
10
9
|
import { uiAccountDescription } from './ui/index.js';
|
|
11
|
-
export const SYNC_TYPES = {
|
|
12
|
-
OBJECT_RECORDS: 'object-records',
|
|
13
|
-
};
|
|
14
10
|
export const SANDBOX_TYPE_MAP = {
|
|
15
11
|
dev: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
16
12
|
developer: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
17
13
|
development: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
18
14
|
standard: HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX,
|
|
19
15
|
};
|
|
20
|
-
export const SANDBOX_API_TYPE_MAP = {
|
|
21
|
-
[HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX]: 1,
|
|
22
|
-
[HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX]: 2,
|
|
23
|
-
};
|
|
24
16
|
export const SANDBOX_TYPE_MAP_V2 = {
|
|
25
17
|
[HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX]: 'STANDARD',
|
|
26
18
|
[HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX]: 'DEVELOPER',
|
|
@@ -45,19 +37,6 @@ export function getHasSandboxesByType(parentAccountConfig, type) {
|
|
|
45
37
|
}
|
|
46
38
|
return false;
|
|
47
39
|
}
|
|
48
|
-
// Fetches available sync types for a given sandbox portal
|
|
49
|
-
export async function getAvailableSyncTypes(parentAccountConfig, config) {
|
|
50
|
-
const parentPortalId = parentAccountConfig.accountId;
|
|
51
|
-
const portalId = config.accountId;
|
|
52
|
-
if (!parentPortalId || !portalId) {
|
|
53
|
-
throw new Error(lib.sandbox.sync.failure.syncTypeFetch);
|
|
54
|
-
}
|
|
55
|
-
const { data: { results: syncTypes }, } = await fetchTypes(parentPortalId, portalId);
|
|
56
|
-
if (!syncTypes) {
|
|
57
|
-
throw new Error(lib.sandbox.sync.failure.syncTypeFetch);
|
|
58
|
-
}
|
|
59
|
-
return syncTypes.map(t => ({ type: t.name }));
|
|
60
|
-
}
|
|
61
40
|
export async function validateSandboxUsageLimits(accountConfig, sandboxType, env) {
|
|
62
41
|
const accountId = accountConfig.accountId;
|
|
63
42
|
if (!accountId) {
|
|
@@ -3,7 +3,6 @@ import { getConfigAccountById } from '@hubspot/local-dev-lib/config';
|
|
|
3
3
|
import { confirmPrompt } from '../../prompts/promptUtils.js';
|
|
4
4
|
import { writeProjectConfig, } from '../../projects/config.js';
|
|
5
5
|
import { ensureProjectExists } from '../../projects/ensureProjectExists.js';
|
|
6
|
-
import { isV2Project } from '../../projects/platformVersion.js';
|
|
7
6
|
import { fetchMigrationApps } from '../../app/migrate.js';
|
|
8
7
|
import { getHasMigratableThemes, validateMigrationAppsAndThemes, handleThemesMigration, migrateThemesV2, } from '../migrate.js';
|
|
9
8
|
import { lib } from '../../../lang/en.js';
|
|
@@ -11,7 +10,6 @@ vi.mock('@hubspot/project-parsing-lib/themes');
|
|
|
11
10
|
vi.mock('../../prompts/promptUtils');
|
|
12
11
|
vi.mock('../../projects/config');
|
|
13
12
|
vi.mock('../../projects/ensureProjectExists');
|
|
14
|
-
vi.mock('../../projects/platformVersion');
|
|
15
13
|
vi.mock('../../app/migrate');
|
|
16
14
|
vi.mock('@hubspot/local-dev-lib/config');
|
|
17
15
|
vi.mock('../../ui/SpinniesManager', () => ({
|
|
@@ -28,7 +26,6 @@ const mockedMigrateThemes = migrateThemes;
|
|
|
28
26
|
const mockedConfirmPrompt = confirmPrompt;
|
|
29
27
|
const mockedWriteProjectConfig = writeProjectConfig;
|
|
30
28
|
const mockedEnsureProjectExists = ensureProjectExists;
|
|
31
|
-
const mockedUseV2Api = isV2Project;
|
|
32
29
|
const mockedFetchMigrationApps = fetchMigrationApps;
|
|
33
30
|
const mockedGetConfigAccountById = getConfigAccountById;
|
|
34
31
|
const ACCOUNT_ID = 123;
|
|
@@ -41,7 +38,6 @@ const createLoadedProjectConfig = (name) => ({
|
|
|
41
38
|
});
|
|
42
39
|
describe('lib/theme/migrate', () => {
|
|
43
40
|
beforeEach(() => {
|
|
44
|
-
mockedUseV2Api.mockReturnValue(false);
|
|
45
41
|
// Mock account config for the test account ID
|
|
46
42
|
mockedGetConfigAccountById.mockReturnValue({
|
|
47
43
|
accountId: ACCOUNT_ID,
|
|
@@ -199,7 +195,7 @@ describe('lib/theme/migrate', () => {
|
|
|
199
195
|
await expect(handleThemesMigration(projectConfig, PLATFORM_VERSION)).rejects.toThrow(lib.migrate.errors.project.failedToMigrateThemes);
|
|
200
196
|
});
|
|
201
197
|
});
|
|
202
|
-
describe('
|
|
198
|
+
describe('migrateThemesV2', () => {
|
|
203
199
|
const options = {
|
|
204
200
|
platformVersion: PLATFORM_VERSION,
|
|
205
201
|
};
|
|
@@ -8,6 +8,7 @@ import { formatTextContents, formatTextContent } from '../../utils/content.js';
|
|
|
8
8
|
import { trackToolUsage } from '../../utils/toolUsageTracking.js';
|
|
9
9
|
import { setupHubSpotConfig } from '../../utils/config.js';
|
|
10
10
|
import { getErrorMessage } from '../../../lib/errorHandlers/index.js';
|
|
11
|
+
import { PLATFORM_VERSIONS } from '@hubspot/local-dev-lib/constants/projects';
|
|
11
12
|
const inputSchema = {
|
|
12
13
|
absoluteCurrentWorkingDirectory,
|
|
13
14
|
name: z
|
|
@@ -40,7 +41,7 @@ export class CreateProjectTool extends Tool {
|
|
|
40
41
|
async handler({ name, destination, projectBase, distribution, auth, features, absoluteCurrentWorkingDirectory, }) {
|
|
41
42
|
setupHubSpotConfig(absoluteCurrentWorkingDirectory);
|
|
42
43
|
await trackToolUsage(toolName);
|
|
43
|
-
let command = addFlag('hs project create', 'platform-version',
|
|
44
|
+
let command = addFlag('hs project create', 'platform-version', PLATFORM_VERSIONS.v2026_03);
|
|
44
45
|
const content = [];
|
|
45
46
|
if (name) {
|
|
46
47
|
command = addFlag(command, 'name', name);
|
|
@@ -55,7 +55,6 @@ describe('mcp-server/tools/project/CreateProjectTool', () => {
|
|
|
55
55
|
stderr: '',
|
|
56
56
|
});
|
|
57
57
|
const result = await tool.handler(baseInput);
|
|
58
|
-
expect(mockAddFlag).toHaveBeenCalledWith('hs project create', 'platform-version', '2025.2');
|
|
59
58
|
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'name', 'test-project');
|
|
60
59
|
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'dest', './test-dest');
|
|
61
60
|
expect(mockAddFlag).toHaveBeenCalledWith(expect.any(String), 'project-base', EMPTY_PROJECT);
|
|
@@ -10,6 +10,7 @@ export declare const features: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
|
10
10
|
webhooks: "webhooks";
|
|
11
11
|
"workflow-action": "workflow-action";
|
|
12
12
|
"app-function": "app-function";
|
|
13
|
+
"app-function-endpoint": "app-function-endpoint";
|
|
13
14
|
"app-object": "app-object";
|
|
14
15
|
scim: "scim";
|
|
15
16
|
}>>>;
|
|
@@ -10,6 +10,7 @@ export const features = z
|
|
|
10
10
|
'card',
|
|
11
11
|
'settings',
|
|
12
12
|
'app-function',
|
|
13
|
+
'app-function-endpoint',
|
|
13
14
|
'webhooks',
|
|
14
15
|
'workflow-action',
|
|
15
16
|
'workflow-action-tool',
|
|
@@ -18,7 +19,7 @@ export const features = z
|
|
|
18
19
|
'scim',
|
|
19
20
|
'page',
|
|
20
21
|
]))
|
|
21
|
-
.describe('The features to include in the project, multiple options can be selected. "app-function" is also known as a
|
|
22
|
+
.describe('The features to include in the project, multiple options can be selected. "app-function" is also known as a private serverless function. "app-function-endpoint" is a serverless functions that is publicly accessible via endpoint. "workflow-action" is also known as a custom workflow action. "workflow-action-tool" is also known as agent tools.')
|
|
22
23
|
.optional();
|
|
23
24
|
export const docsSearchQuery = z
|
|
24
25
|
.string()
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { uiLogger } from '../ui/logger.js';
|
|
2
|
-
import { initiateSync } from '@hubspot/local-dev-lib/api/sandboxSync';
|
|
3
|
-
import { getConfigAccountIfExists, getConfigAccountById, } from '@hubspot/local-dev-lib/config';
|
|
4
|
-
import { HUBSPOT_ACCOUNT_TYPES } from '@hubspot/local-dev-lib/constants/config';
|
|
5
|
-
import { mockHubSpotHttpError } from '../testUtils.js';
|
|
6
|
-
import { getAvailableSyncTypes } from '../sandboxes.js';
|
|
7
|
-
import { syncSandbox } from '../sandboxSync.js';
|
|
8
|
-
import SpinniesManager from '../ui/SpinniesManager.js';
|
|
9
|
-
vi.mock('@hubspot/local-dev-lib/api/sandboxSync');
|
|
10
|
-
vi.mock('@hubspot/local-dev-lib/config');
|
|
11
|
-
vi.mock('../sandboxes');
|
|
12
|
-
vi.mock('../ui/SpinniesManager');
|
|
13
|
-
const mockedUiLogger = uiLogger;
|
|
14
|
-
const mockedInitiateSync = initiateSync;
|
|
15
|
-
const mockedGetConfigAccountIfExists = getConfigAccountIfExists;
|
|
16
|
-
const mockedGetConfigAccountById = getConfigAccountById;
|
|
17
|
-
const mockedGetAvailableSyncTypes = getAvailableSyncTypes;
|
|
18
|
-
const mockedSpinniesInit = SpinniesManager.init;
|
|
19
|
-
const mockedSpinniesAdd = SpinniesManager.add;
|
|
20
|
-
const mockedSpinniesSucceed = SpinniesManager.succeed;
|
|
21
|
-
const mockedSpinniesFail = SpinniesManager.fail;
|
|
22
|
-
describe('lib/sandboxSync', () => {
|
|
23
|
-
const mockEnv = 'qa';
|
|
24
|
-
const mockParentAccount = {
|
|
25
|
-
name: 'Parent Account',
|
|
26
|
-
accountId: 123,
|
|
27
|
-
accountType: HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX,
|
|
28
|
-
env: mockEnv,
|
|
29
|
-
authType: 'personalaccesskey',
|
|
30
|
-
};
|
|
31
|
-
const mockChildAccount = {
|
|
32
|
-
name: 'Child Account',
|
|
33
|
-
accountId: 456,
|
|
34
|
-
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
35
|
-
env: mockEnv,
|
|
36
|
-
authType: 'personalaccesskey',
|
|
37
|
-
};
|
|
38
|
-
const mockChildAccountWithMissingId = {
|
|
39
|
-
name: 'Child Account',
|
|
40
|
-
accountType: HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX,
|
|
41
|
-
env: mockEnv,
|
|
42
|
-
authType: 'personalaccesskey',
|
|
43
|
-
};
|
|
44
|
-
const mockSyncTasks = [{ type: 'mock-sync-type' }];
|
|
45
|
-
beforeEach(() => {
|
|
46
|
-
mockedGetConfigAccountIfExists
|
|
47
|
-
.mockReturnValueOnce(mockChildAccount)
|
|
48
|
-
.mockReturnValueOnce(mockParentAccount);
|
|
49
|
-
mockedGetAvailableSyncTypes.mockResolvedValue(mockSyncTasks);
|
|
50
|
-
// Mock SpinniesManager methods to prevent spinner errors
|
|
51
|
-
mockedSpinniesInit.mockImplementation(() => { });
|
|
52
|
-
mockedSpinniesAdd.mockImplementation(() => { });
|
|
53
|
-
mockedSpinniesSucceed.mockImplementation(() => { });
|
|
54
|
-
mockedSpinniesFail.mockImplementation(() => { });
|
|
55
|
-
// Mock account config for uiAccountDescription calls
|
|
56
|
-
mockedGetConfigAccountById.mockImplementation(accountId => {
|
|
57
|
-
if (accountId === mockChildAccount.accountId) {
|
|
58
|
-
return mockChildAccount;
|
|
59
|
-
}
|
|
60
|
-
if (accountId === mockParentAccount.accountId) {
|
|
61
|
-
return mockParentAccount;
|
|
62
|
-
}
|
|
63
|
-
return undefined; // Don't throw, just return undefined for unknown accounts
|
|
64
|
-
});
|
|
65
|
-
});
|
|
66
|
-
describe('syncSandbox()', () => {
|
|
67
|
-
it('successfully syncs a sandbox with provided sync tasks', async () => {
|
|
68
|
-
mockedInitiateSync.mockResolvedValue({ status: 'SUCCESS' });
|
|
69
|
-
await syncSandbox(mockChildAccount, mockParentAccount, mockEnv, mockSyncTasks);
|
|
70
|
-
expect(mockedSpinniesInit).toHaveBeenCalled();
|
|
71
|
-
expect(mockedSpinniesAdd).toHaveBeenCalled();
|
|
72
|
-
expect(mockedInitiateSync).toHaveBeenCalledWith(mockParentAccount.accountId, mockChildAccount.accountId, mockSyncTasks, mockChildAccount.accountId);
|
|
73
|
-
expect(mockedSpinniesSucceed).toHaveBeenCalled();
|
|
74
|
-
});
|
|
75
|
-
it('fetches sync types when no tasks are provided', async () => {
|
|
76
|
-
mockedInitiateSync.mockResolvedValue({ status: 'SUCCESS' });
|
|
77
|
-
await syncSandbox(mockChildAccount, mockParentAccount, mockEnv, []);
|
|
78
|
-
expect(mockedGetAvailableSyncTypes).toHaveBeenCalledWith(mockParentAccount, mockChildAccount);
|
|
79
|
-
expect(mockedGetAvailableSyncTypes).toHaveBeenCalledWith(mockParentAccount, mockChildAccount);
|
|
80
|
-
expect(mockedInitiateSync).toHaveBeenCalled();
|
|
81
|
-
});
|
|
82
|
-
it('throws error when account IDs are missing', async () => {
|
|
83
|
-
const errorRegex = new RegExp(`because your account has been removed from`);
|
|
84
|
-
await expect(syncSandbox(mockChildAccountWithMissingId, mockParentAccount, mockEnv, mockSyncTasks)).rejects.toThrow(errorRegex);
|
|
85
|
-
});
|
|
86
|
-
it('handles sync in progress error', async () => {
|
|
87
|
-
const error = mockHubSpotHttpError('', {
|
|
88
|
-
status: 429,
|
|
89
|
-
data: {
|
|
90
|
-
category: 'RATE_LIMITS',
|
|
91
|
-
subCategory: 'sandboxes-sync-api.SYNC_IN_PROGRESS',
|
|
92
|
-
},
|
|
93
|
-
});
|
|
94
|
-
mockedInitiateSync.mockRejectedValue(error);
|
|
95
|
-
await expect(syncSandbox(mockChildAccount, mockParentAccount, mockEnv, mockSyncTasks)).rejects.toEqual(error);
|
|
96
|
-
expect(mockedSpinniesFail).toHaveBeenCalled();
|
|
97
|
-
expect(mockedUiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Couldn't run the sync because there's another sync in progress/));
|
|
98
|
-
});
|
|
99
|
-
it('handles invalid user error', async () => {
|
|
100
|
-
const error = mockHubSpotHttpError('', {
|
|
101
|
-
status: 403,
|
|
102
|
-
data: {
|
|
103
|
-
category: 'BANNED',
|
|
104
|
-
subCategory: 'sandboxes-sync-api.SYNC_NOT_ALLOWED_INVALID_USER',
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
mockedInitiateSync.mockRejectedValue(error);
|
|
108
|
-
await expect(syncSandbox(mockChildAccount, mockParentAccount, mockEnv, mockSyncTasks)).rejects.toEqual(error);
|
|
109
|
-
expect(mockedSpinniesFail).toHaveBeenCalled();
|
|
110
|
-
expect(mockedUiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/because your account has been removed from/));
|
|
111
|
-
});
|
|
112
|
-
it('handles not super admin error', async () => {
|
|
113
|
-
const error = mockHubSpotHttpError('', {
|
|
114
|
-
status: 403,
|
|
115
|
-
data: {
|
|
116
|
-
category: 'BANNED',
|
|
117
|
-
subCategory: 'sandboxes-sync-api.SYNC_NOT_ALLOWED_INVALID_USERID',
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
mockedInitiateSync.mockRejectedValue(error);
|
|
121
|
-
await expect(syncSandbox(mockChildAccount, mockParentAccount, mockEnv, mockSyncTasks)).rejects.toEqual(error);
|
|
122
|
-
expect(mockedSpinniesFail).toHaveBeenCalled();
|
|
123
|
-
expect(mockedUiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/Couldn't run the sync because you are not a super admin in/));
|
|
124
|
-
});
|
|
125
|
-
it('handles sandbox not found error', async () => {
|
|
126
|
-
const error = mockHubSpotHttpError('', {
|
|
127
|
-
status: 404,
|
|
128
|
-
data: {
|
|
129
|
-
category: 'OBJECT_NOT_FOUND',
|
|
130
|
-
subCategory: 'SandboxErrors.SANDBOX_NOT_FOUND',
|
|
131
|
-
},
|
|
132
|
-
});
|
|
133
|
-
mockedInitiateSync.mockRejectedValue(error);
|
|
134
|
-
await expect(syncSandbox(mockChildAccount, mockParentAccount, mockEnv, mockSyncTasks)).rejects.toEqual(error);
|
|
135
|
-
expect(mockedSpinniesFail).toHaveBeenCalled();
|
|
136
|
-
expect(mockedUiLogger.error).toHaveBeenCalledWith(expect.stringMatching(/may have been deleted through the UI/));
|
|
137
|
-
});
|
|
138
|
-
it('displays slim info message when specified', async () => {
|
|
139
|
-
mockedInitiateSync.mockResolvedValue({ status: 'SUCCESS' });
|
|
140
|
-
await syncSandbox(mockChildAccount, mockParentAccount, mockEnv, mockSyncTasks, true);
|
|
141
|
-
expect(mockedUiLogger.info).not.toHaveBeenCalled();
|
|
142
|
-
expect(mockedSpinniesSucceed).toHaveBeenCalledWith('sandboxSync', expect.objectContaining({
|
|
143
|
-
text: expect.stringMatching(/Initiated sync of object definitions from production to /),
|
|
144
|
-
}));
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
});
|
package/lib/sandboxSync.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { HubSpotConfigAccount } from '@hubspot/local-dev-lib/types/Accounts';
|
|
2
|
-
import { Environment } from '@hubspot/local-dev-lib/types/Accounts';
|
|
3
|
-
import { SandboxSyncTask } from '../types/Sandboxes.js';
|
|
4
|
-
export declare function syncSandbox(accountConfig: HubSpotConfigAccount, parentAccountConfig: HubSpotConfigAccount, env: Environment, syncTasks: Array<SandboxSyncTask>, slimInfoMessage?: boolean): Promise<void>;
|
package/lib/sandboxSync.js
DELETED
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import SpinniesManager from './ui/SpinniesManager.js';
|
|
2
|
-
import { getHubSpotWebsiteOrigin } from '@hubspot/local-dev-lib/urls';
|
|
3
|
-
import { uiLogger } from './ui/logger.js';
|
|
4
|
-
import { initiateSync } from '@hubspot/local-dev-lib/api/sandboxSync';
|
|
5
|
-
import { isSpecifiedError } from '@hubspot/local-dev-lib/errors/index';
|
|
6
|
-
import { lib } from '../lang/en.js';
|
|
7
|
-
import { getAvailableSyncTypes, getSandboxTypeAsString } from './sandboxes.js';
|
|
8
|
-
import { debugError, logError, ApiErrorContext, } from './errorHandlers/index.js';
|
|
9
|
-
import { uiAccountDescription, uiLine, uiCommandDisabledBanner, } from './ui/index.js';
|
|
10
|
-
import { isDevelopmentSandbox } from './accountTypes.js';
|
|
11
|
-
export async function syncSandbox(accountConfig, parentAccountConfig, env, syncTasks, slimInfoMessage = false) {
|
|
12
|
-
const accountId = accountConfig.accountId;
|
|
13
|
-
const parentAccountId = parentAccountConfig.accountId;
|
|
14
|
-
const isDevSandbox = isDevelopmentSandbox(accountConfig);
|
|
15
|
-
if (!accountId || !parentAccountId) {
|
|
16
|
-
throw new Error(lib.sandbox.sync.failure.invalidUser(uiAccountDescription(accountId), uiAccountDescription(parentAccountId)));
|
|
17
|
-
}
|
|
18
|
-
SpinniesManager.init({
|
|
19
|
-
succeedColor: 'white',
|
|
20
|
-
});
|
|
21
|
-
let availableSyncTasks = syncTasks;
|
|
22
|
-
const baseUrl = getHubSpotWebsiteOrigin(env);
|
|
23
|
-
const syncStatusUrl = `${baseUrl}/sandboxes-developer/${parentAccountId}/${getSandboxTypeAsString(accountConfig.accountType)}`;
|
|
24
|
-
try {
|
|
25
|
-
// If no sync tasks exist, fetch sync types based on default account. Parent account required for fetch
|
|
26
|
-
if (!availableSyncTasks ||
|
|
27
|
-
(typeof availableSyncTasks === 'object' &&
|
|
28
|
-
availableSyncTasks.length === 0)) {
|
|
29
|
-
availableSyncTasks = await getAvailableSyncTypes(parentAccountConfig, accountConfig);
|
|
30
|
-
}
|
|
31
|
-
SpinniesManager.add('sandboxSync', {
|
|
32
|
-
text: lib.sandbox.sync.loading.startSync,
|
|
33
|
-
});
|
|
34
|
-
await initiateSync(parentAccountId, accountId, availableSyncTasks, accountId);
|
|
35
|
-
const spinniesText = isDevSandbox
|
|
36
|
-
? lib.sandbox.sync.loading.succeedDevSb(accountId)
|
|
37
|
-
: lib.sandbox.sync.loading.succeed(accountId);
|
|
38
|
-
SpinniesManager.succeed('sandboxSync', {
|
|
39
|
-
text: slimInfoMessage
|
|
40
|
-
? lib.sandbox.sync.loading.successDevSbInfo(accountId, syncStatusUrl)
|
|
41
|
-
: spinniesText,
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
catch (err) {
|
|
45
|
-
debugError(err);
|
|
46
|
-
SpinniesManager.fail('sandboxSync', {
|
|
47
|
-
text: lib.sandbox.sync.loading.fail(accountId),
|
|
48
|
-
});
|
|
49
|
-
uiLogger.log('');
|
|
50
|
-
if (isSpecifiedError(err, {
|
|
51
|
-
statusCode: 403,
|
|
52
|
-
category: 'BANNED',
|
|
53
|
-
subCategory: 'sandboxes-sync-api.SYNC_NOT_ALLOWED_INVALID_USER',
|
|
54
|
-
})) {
|
|
55
|
-
uiLogger.error(lib.sandbox.sync.failure.invalidUser(uiAccountDescription(accountId), uiAccountDescription(parentAccountId)));
|
|
56
|
-
}
|
|
57
|
-
else if (isSpecifiedError(err, {
|
|
58
|
-
statusCode: 429,
|
|
59
|
-
category: 'RATE_LIMITS',
|
|
60
|
-
subCategory: 'sandboxes-sync-api.SYNC_IN_PROGRESS',
|
|
61
|
-
})) {
|
|
62
|
-
uiLogger.error(lib.sandbox.sync.failure.syncInProgress(`${baseUrl}/sandboxes-developer/${parentAccountId}/syncactivitylog`));
|
|
63
|
-
}
|
|
64
|
-
else if (isSpecifiedError(err, {
|
|
65
|
-
statusCode: 403,
|
|
66
|
-
category: 'BANNED',
|
|
67
|
-
subCategory: 'sandboxes-sync-api.SYNC_NOT_ALLOWED_INVALID_USERID',
|
|
68
|
-
})) {
|
|
69
|
-
// This will only trigger if a user is not a super admin of the target account.
|
|
70
|
-
uiLogger.error(lib.sandbox.sync.failure.notSuperAdmin(accountId));
|
|
71
|
-
}
|
|
72
|
-
else if (isSpecifiedError(err, {
|
|
73
|
-
statusCode: 404,
|
|
74
|
-
category: 'OBJECT_NOT_FOUND',
|
|
75
|
-
subCategory: 'SandboxErrors.SANDBOX_NOT_FOUND',
|
|
76
|
-
})) {
|
|
77
|
-
uiLogger.error(lib.sandbox.sync.failure.objectNotFound(accountId));
|
|
78
|
-
}
|
|
79
|
-
else if (isSpecifiedError(err, {
|
|
80
|
-
statusCode: 404,
|
|
81
|
-
})) {
|
|
82
|
-
uiCommandDisabledBanner('hs sandbox sync', 'https://developers.hubspot.com/docs/developer-tooling/local-development/hubspot-cli/project-commands');
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
logError(err, new ApiErrorContext({
|
|
86
|
-
accountId: parentAccountId,
|
|
87
|
-
request: 'sandbox sync',
|
|
88
|
-
}));
|
|
89
|
-
}
|
|
90
|
-
uiLogger.log('');
|
|
91
|
-
throw err;
|
|
92
|
-
}
|
|
93
|
-
if (!slimInfoMessage) {
|
|
94
|
-
uiLogger.log('');
|
|
95
|
-
uiLine();
|
|
96
|
-
uiLogger.info(isDevSandbox
|
|
97
|
-
? lib.sandbox.sync.info.syncMessageDevSb(syncStatusUrl)
|
|
98
|
-
: lib.sandbox.sync.info.syncMessage(syncStatusUrl));
|
|
99
|
-
uiLine();
|
|
100
|
-
uiLogger.log('');
|
|
101
|
-
}
|
|
102
|
-
}
|