@hubspot/local-dev-lib 0.4.1-experimental.0 → 0.4.3-experimental.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/api/appsDev.d.ts CHANGED
@@ -5,3 +5,4 @@ export declare function fetchPublicAppDeveloperTestAccountInstallData(appId: num
5
5
  export declare function fetchPublicAppProductionInstallCounts(appId: number, accountId: number): HubSpotPromise<PublicAppInstallCounts>;
6
6
  export declare function fetchPublicAppMetadata(appId: number, accountId: number): HubSpotPromise<PublicApp>;
7
7
  export declare function installStaticAuthAppOnTestAccount(appId: number, accountId: number, scopeGroupIds: number[]): HubSpotPromise<void>;
8
+ export declare function fetchAppMetadataByUid(appUid: string, accountId: number): HubSpotPromise<PublicApp>;
package/api/appsDev.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.installStaticAuthAppOnTestAccount = exports.fetchPublicAppMetadata = exports.fetchPublicAppProductionInstallCounts = exports.fetchPublicAppDeveloperTestAccountInstallData = exports.fetchPublicAppsForPortal = void 0;
3
+ exports.fetchAppMetadataByUid = exports.installStaticAuthAppOnTestAccount = exports.fetchPublicAppMetadata = exports.fetchPublicAppProductionInstallCounts = exports.fetchPublicAppDeveloperTestAccountInstallData = exports.fetchPublicAppsForPortal = void 0;
4
4
  const http_1 = require("../http");
5
5
  const APPS_DEV_API_PATH = 'apps-dev/external/public/v3';
6
6
  const APPS_HUBLETS_API_PATH = 'apps-hublets/external/static-token/v3';
@@ -39,3 +39,12 @@ function installStaticAuthAppOnTestAccount(appId, accountId, scopeGroupIds) {
39
39
  });
40
40
  }
41
41
  exports.installStaticAuthAppOnTestAccount = installStaticAuthAppOnTestAccount;
42
+ function fetchAppMetadataByUid(appUid, accountId) {
43
+ return http_1.http.get(accountId, {
44
+ url: `${APPS_DEV_API_PATH}/full/portal/sourceId`,
45
+ params: {
46
+ sourceId: appUid,
47
+ },
48
+ });
49
+ }
50
+ exports.fetchAppMetadataByUid = fetchAppMetadataByUid;
package/api/crm.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { HubSpotPromise } from '../types/Http';
2
+ import { ImportRequest, ImportResponse } from '../types/Crm';
3
+ export declare function createImport(accountId: number, importRequest: ImportRequest, dataFileNames: string[]): HubSpotPromise<ImportResponse>;
package/api/crm.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createImport = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const form_data_1 = __importDefault(require("form-data"));
10
+ const http_1 = require("../http");
11
+ const path_2 = require("../lib/path");
12
+ const HUBSPOT_CRM_IMPORT_PATH = '/crm/v3/imports';
13
+ function createImport(accountId, importRequest, dataFileNames) {
14
+ const jsonImportRequest = JSON.stringify(importRequest);
15
+ const formData = new form_data_1.default();
16
+ formData.append('importRequest', jsonImportRequest);
17
+ dataFileNames.forEach(file => {
18
+ const stream = fs_extra_1.default.createReadStream(path_1.default.resolve((0, path_2.getCwd)(), file));
19
+ formData.append('files', stream, file);
20
+ });
21
+ return http_1.http.post(accountId, {
22
+ url: `${HUBSPOT_CRM_IMPORT_PATH}`,
23
+ data: formData,
24
+ headers: {
25
+ ...formData.getHeaders(),
26
+ },
27
+ });
28
+ }
29
+ exports.createImport = createImport;
package/api/github.js CHANGED
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.fetchRepoContents = exports.fetchRepoFileByDownloadUrl = exports.fetchRepoFile = exports.fetchRepoAsZip = exports.fetchRepoReleaseData = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const getAxiosConfig_1 = require("../http/getAxiosConfig");
9
+ const errors_1 = require("../errors");
9
10
  const GITHUB_REPOS_API = 'https://api.github.com/repos';
10
11
  const GITHUB_RAW_CONTENT_API_PATH = 'https://raw.githubusercontent.com';
11
12
  function getAdditionalHeaders() {
@@ -18,16 +19,33 @@ function getAdditionalHeaders() {
18
19
  }
19
20
  return headers;
20
21
  }
22
+ function githubRequestWithFallback(url, responseType) {
23
+ const headersWithAuth = {
24
+ ...(0, getAxiosConfig_1.getDefaultUserAgentHeader)(),
25
+ ...getAdditionalHeaders(),
26
+ };
27
+ if (headersWithAuth.authorization) {
28
+ return axios_1.default
29
+ .get(url, { headers: headersWithAuth, responseType })
30
+ .catch(error => {
31
+ // 404 with an auth token might mean an SSO issue so retry without the authorization header
32
+ if ((0, errors_1.isSpecifiedError)(error, { statusCode: 404 })) {
33
+ return axios_1.default.get(url, {
34
+ headers: { ...(0, getAxiosConfig_1.getDefaultUserAgentHeader)() },
35
+ responseType,
36
+ });
37
+ }
38
+ throw error;
39
+ });
40
+ }
41
+ // No auth token, proceed normally
42
+ return axios_1.default.get(url, { headers: headersWithAuth, responseType });
43
+ }
21
44
  // Returns information about the repo's releases. Defaults to "latest" if no tag is provided
22
45
  // https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#get-a-release-by-tag-name
23
46
  function fetchRepoReleaseData(repoPath, tag = '') {
24
47
  const URL = `${GITHUB_REPOS_API}/${repoPath}/releases`;
25
- return axios_1.default.get(`${URL}/${tag ? `tags/${tag}` : 'latest'}`, {
26
- headers: {
27
- ...(0, getAxiosConfig_1.getDefaultUserAgentHeader)(),
28
- ...getAdditionalHeaders(),
29
- },
30
- });
48
+ return githubRequestWithFallback(`${URL}/${tag ? `tags/${tag}` : 'latest'}`);
31
49
  }
32
50
  exports.fetchRepoReleaseData = fetchRepoReleaseData;
33
51
  // Returns the entire repo content as a zip, using the zipball_url from fetchRepoReleaseData()
@@ -41,31 +59,19 @@ function fetchRepoAsZip(zipUrl) {
41
59
  exports.fetchRepoAsZip = fetchRepoAsZip;
42
60
  // Returns the raw file contents via the raw.githubusercontent endpoint
43
61
  function fetchRepoFile(repoPath, filePath, ref) {
44
- return axios_1.default.get(`${GITHUB_RAW_CONTENT_API_PATH}/${repoPath}/${ref}/${filePath}`, {
45
- headers: {
46
- ...(0, getAxiosConfig_1.getDefaultUserAgentHeader)(),
47
- ...getAdditionalHeaders(),
48
- },
49
- });
62
+ const url = `${GITHUB_RAW_CONTENT_API_PATH}/${repoPath}/${ref}/${filePath}`;
63
+ return githubRequestWithFallback(url);
50
64
  }
51
65
  exports.fetchRepoFile = fetchRepoFile;
52
66
  // Returns the raw file contents via the raw.githubusercontent endpoint
53
67
  function fetchRepoFileByDownloadUrl(downloadUrl) {
54
- return axios_1.default.get(downloadUrl, {
55
- headers: { ...(0, getAxiosConfig_1.getDefaultUserAgentHeader)(), ...getAdditionalHeaders() },
56
- responseType: 'arraybuffer',
57
- });
68
+ return githubRequestWithFallback(downloadUrl, 'arraybuffer');
58
69
  }
59
70
  exports.fetchRepoFileByDownloadUrl = fetchRepoFileByDownloadUrl;
60
71
  // Returns the contents of a file or directory in a repository by path
61
72
  // https://docs.github.com/en/rest/repos/contents?apiVersion=2022-11-28#get-repository-content
62
73
  function fetchRepoContents(repoPath, path, ref) {
63
74
  const refQuery = ref ? `?ref=${ref}` : '';
64
- return axios_1.default.get(`${GITHUB_REPOS_API}/${repoPath}/contents/${path}${refQuery}`, {
65
- headers: {
66
- ...(0, getAxiosConfig_1.getDefaultUserAgentHeader)(),
67
- ...getAdditionalHeaders(),
68
- },
69
- });
75
+ return githubRequestWithFallback(`${GITHUB_REPOS_API}/${repoPath}/contents/${path}${refQuery}`);
70
76
  }
71
77
  exports.fetchRepoContents = fetchRepoContents;
@@ -7,4 +7,4 @@ export declare function fetchAccessToken(personalAccessKey: string, env?: Enviro
7
7
  export declare function fetchScopeData(accountId: number, scopeGroup: string): HubSpotPromise<ScopeData>;
8
8
  export declare function fetchScopeAuthorizationData(accountId: number): HubSpotPromise<ScopeAuthorizationResponse>;
9
9
  export declare function fetchAppInstallationData(portalId: number, projectId: number, appUid: string, requiredScopeGroups: Array<string>, optionalScopeGroups?: Array<string>): HubSpotPromise<PublicAppInstallationData>;
10
- export declare function fetchEnabledFeatures(accountId: number): Promise<import("axios").AxiosResponse<EnabledFeaturesResponse, any>>;
10
+ export declare function fetchEnabledFeatures(accountId: number): Promise<import("axios").AxiosResponse<EnabledFeaturesResponse, any, {}>>;
@@ -46,7 +46,7 @@ class _CLIConfiguration {
46
46
  const configFromEnv = (0, environment_1.loadConfigFromEnvironment)();
47
47
  if (configFromEnv) {
48
48
  logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.load.configFromEnv`, {
49
- accountId: configFromEnv.accounts[0].accountId,
49
+ accountId: `${configFromEnv.accounts?.[0].accountId}`,
50
50
  }));
51
51
  this.useEnvConfig = true;
52
52
  this.config = this.handleLegacyCmsPublishMode(configFromEnv);
@@ -168,11 +168,11 @@ class _CLIConfiguration {
168
168
  }
169
169
  let account = null;
170
170
  if (name) {
171
- account = this.config.accounts.find(a => a.name === name) || null;
171
+ account = this.config.accounts?.find(a => a.name === name) || null;
172
172
  }
173
173
  if (accountId && !account) {
174
174
  account =
175
- this.config.accounts.find(a => accountId === a.accountId) || null;
175
+ this.config.accounts?.find(a => accountId === a.accountId) || null;
176
176
  }
177
177
  return account;
178
178
  }
@@ -230,7 +230,7 @@ class _CLIConfiguration {
230
230
  return account.name || account.accountId;
231
231
  }
232
232
  getAccountIndex(accountId) {
233
- return this.config
233
+ return this.config && Array.isArray(this.config.accounts)
234
234
  ? this.config.accounts.findIndex(account => account.accountId === accountId)
235
235
  : -1;
236
236
  }
@@ -243,10 +243,10 @@ class _CLIConfiguration {
243
243
  isAccountInConfig(nameOrId) {
244
244
  if (typeof nameOrId === 'string') {
245
245
  return (!!this.config &&
246
- this.config.accounts &&
246
+ !!this.config.accounts &&
247
247
  !!this.getAccountId(nameOrId.toLowerCase()));
248
248
  }
249
- return (!!this.config && this.config.accounts && !!this.getAccountId(nameOrId));
249
+ return (!!this.config && !!this.config.accounts && !!this.getAccountId(nameOrId));
250
250
  }
251
251
  getAndLoadConfigIfNeeded(options) {
252
252
  if (!this.config) {
@@ -341,7 +341,7 @@ class _CLIConfiguration {
341
341
  safelyApplyUpdates('accountType', this.getAccountType(updatedAccountType, sandboxAccountType));
342
342
  safelyApplyUpdates('parentAccountId', parentAccountId);
343
343
  const completedAccountConfig = nextAccountConfig;
344
- if (!Object.hasOwn(this.config, 'accounts')) {
344
+ if (!Array.isArray(this.config.accounts)) {
345
345
  this.config.accounts = [];
346
346
  }
347
347
  if (currentAccountConfig) {
@@ -429,7 +429,10 @@ class _CLIConfiguration {
429
429
  if (accountConfig) {
430
430
  logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.removeAccountFromConfig.deleting`, { accountId }));
431
431
  const index = this.getAccountIndex(accountId);
432
- this.config.accounts.splice(index, 1);
432
+ if (index === -1) {
433
+ return removedAccountIsDefault;
434
+ }
435
+ this.config.accounts?.splice(index, 1);
433
436
  if (this.getDefaultAccount() === accountConfig.name) {
434
437
  removedAccountIsDefault = true;
435
438
  }
@@ -24,7 +24,7 @@ function getOrderedConfig(unorderedConfig) {
24
24
  httpTimeout,
25
25
  allowUsageTracking,
26
26
  ...rest,
27
- accounts: accounts.map(getOrderedAccount),
27
+ accounts: accounts?.map(getOrderedAccount) || [],
28
28
  };
29
29
  }
30
30
  exports.getOrderedConfig = getOrderedConfig;
@@ -80,7 +80,7 @@ function generateConfig(type, options) {
80
80
  return null;
81
81
  }
82
82
  if (configAccount) {
83
- config.accounts.push(configAccount);
83
+ config.accounts?.push(configAccount);
84
84
  }
85
85
  return config;
86
86
  }
@@ -14,7 +14,6 @@ const auth_1 = require("../constants/auth");
14
14
  const files_1 = require("../constants/files");
15
15
  const environment_1 = require("../lib/environment");
16
16
  const logger_1 = require("../lib/logger");
17
- const git_1 = require("../utils/git");
18
17
  const errors_DEPRECATED_1 = require("../errors/errors_DEPRECATED");
19
18
  const ALL_CMS_PUBLISH_MODES = Object.values(files_1.CMS_PUBLISH_MODE);
20
19
  let _config;
@@ -191,12 +190,11 @@ function readConfigFile() {
191
190
  return { source, error };
192
191
  }
193
192
  try {
194
- (0, git_1.isConfigPathInGitRepo)(_configPath);
195
193
  source = fs_extra_1.default.readFileSync(_configPath);
196
194
  }
197
195
  catch (err) {
198
196
  error = err;
199
- logger_1.logger.error('Config file could not be read "%s"', _configPath);
197
+ logger_1.logger.error(`Config file could not be read: ${_configPath}`);
200
198
  (0, errors_DEPRECATED_1.logFileSystemErrorInstance)(error, {
201
199
  filepath: _configPath,
202
200
  operation: 'read',
@@ -215,7 +213,7 @@ function parseConfig(configSource) {
215
213
  }
216
214
  catch (err) {
217
215
  error = err;
218
- logger_1.logger.error('Config file could not be parsed "%s"', _configPath);
216
+ logger_1.logger.error(`Config file could not be parsed: ${_configPath}`);
219
217
  (0, errors_DEPRECATED_1.logErrorInstance)(err);
220
218
  }
221
219
  return { parsed, error };
package/config/migrate.js CHANGED
@@ -105,6 +105,8 @@ function mergeConfigProperties(globalConfig, deprecatedConfig, force) {
105
105
  config_1.ENV,
106
106
  config_1.HTTP_USE_LOCALHOST,
107
107
  config_1.ALLOW_USAGE_TRACKING,
108
+ config_1.AUTO_OPEN_BROWSER,
109
+ config_1.ALLOW_AUTO_UPDATES,
108
110
  ];
109
111
  const conflicts = [];
110
112
  propertiesToCheck.forEach(prop => {
@@ -0,0 +1,3 @@
1
+ import { HubSpotState } from '../types/Config';
2
+ export declare function getStateValue<K extends keyof HubSpotState>(key: K): HubSpotState[K];
3
+ export declare function setStateValue<K extends keyof HubSpotState>(key: K, value: HubSpotState[K]): void;
@@ -0,0 +1,104 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.setStateValue = exports.getStateValue = void 0;
27
+ const fs = __importStar(require("fs"));
28
+ const path = __importStar(require("path"));
29
+ const lang_1 = require("../utils/lang");
30
+ const config_1 = require("../constants/config");
31
+ const logger_1 = require("../lib/logger");
32
+ const i18nKey = 'config.state';
33
+ const DEFAULT_STATE = {
34
+ mcpTotalToolCalls: 0,
35
+ };
36
+ function ensureCLIDirectory() {
37
+ try {
38
+ const dir = path.dirname(config_1.STATE_FILE_PATH);
39
+ if (!fs.existsSync(dir)) {
40
+ fs.mkdirSync(dir, { recursive: true });
41
+ }
42
+ }
43
+ catch (error) {
44
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.ensureCLIDirectory.errors.cannotCreateDirectory`, {
45
+ error: error instanceof Error ? error.message : String(error),
46
+ }));
47
+ }
48
+ }
49
+ function sanitizeAndMerge(parsed) {
50
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
51
+ return structuredClone(DEFAULT_STATE);
52
+ }
53
+ const state = parsed;
54
+ const result = structuredClone(DEFAULT_STATE);
55
+ for (const key in DEFAULT_STATE) {
56
+ const typedKey = key;
57
+ if (key in state &&
58
+ typeof state[typedKey] === typeof DEFAULT_STATE[typedKey]) {
59
+ result[typedKey] = state[typedKey];
60
+ }
61
+ // keys not in parsed file remain as DEFAULT values
62
+ }
63
+ return result;
64
+ }
65
+ function getCurrentState() {
66
+ try {
67
+ if (!fs.existsSync(config_1.STATE_FILE_PATH)) {
68
+ return structuredClone(DEFAULT_STATE);
69
+ }
70
+ const data = fs.readFileSync(config_1.STATE_FILE_PATH, 'utf-8');
71
+ if (!data?.trim()) {
72
+ logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.getCurrentState.debug.emptyStateFile`));
73
+ return structuredClone(DEFAULT_STATE);
74
+ }
75
+ const parsed = JSON.parse(data);
76
+ return sanitizeAndMerge(parsed);
77
+ }
78
+ catch (error) {
79
+ logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.getCurrentState.errors.errorReading`, {
80
+ error: error instanceof Error ? error.message : String(error),
81
+ }));
82
+ return structuredClone(DEFAULT_STATE);
83
+ }
84
+ }
85
+ function getStateValue(key) {
86
+ ensureCLIDirectory();
87
+ const state = getCurrentState();
88
+ return state[key];
89
+ }
90
+ exports.getStateValue = getStateValue;
91
+ function setStateValue(key, value) {
92
+ ensureCLIDirectory();
93
+ const currentState = getCurrentState();
94
+ const newState = { ...currentState, [key]: value };
95
+ try {
96
+ fs.writeFileSync(config_1.STATE_FILE_PATH, JSON.stringify(newState, null, 2), 'utf-8');
97
+ }
98
+ catch (error) {
99
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.setStateValue.errors.failedToWrite`, {
100
+ error: error instanceof Error ? error.message : String(error),
101
+ }));
102
+ }
103
+ }
104
+ exports.setStateValue = setStateValue;
@@ -2,7 +2,9 @@ export declare const DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME = "hubspot.config.yml
2
2
  export declare const ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME = "archived.hubspot.config.yml";
3
3
  export declare const HUBSPOT_CONFIGURATION_FOLDER = ".hscli";
4
4
  export declare const HUBSPOT_CONFIGURATION_FILE = "config.yml";
5
+ export declare const HUBSPOT_STATE_FILE = "state.json";
5
6
  export declare const GLOBAL_CONFIG_PATH: string;
7
+ export declare const STATE_FILE_PATH: string;
6
8
  export declare const DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME = ".hsaccount";
7
9
  export declare const DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID = "DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID";
8
10
  export declare const DEFAULT_ACCOUNT_OVERRIDE_ERROR_ACCOUNT_NOT_FOUND = "DEFAULT_ACCOUNT_OVERRIDE_ERROR_ACCOUNT_NOT_FOUND";
@@ -11,6 +13,8 @@ export declare const HTTP_TIMEOUT = "httpTimeout";
11
13
  export declare const ENV = "env";
12
14
  export declare const HTTP_USE_LOCALHOST = "httpUseLocalhost";
13
15
  export declare const ALLOW_USAGE_TRACKING = "allowUsageTracking";
16
+ export declare const AUTO_OPEN_BROWSER = "autoOpenBrowser";
17
+ export declare const ALLOW_AUTO_UPDATES = "allowAutoUpdates";
14
18
  export declare const DEFAULT_ACCOUNT = "defaultAccount";
15
19
  export declare const DEFAULT_PORTAL = "defaultPortal";
16
20
  export declare const MIN_HTTP_TIMEOUT = 3000;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.HUBSPOT_ACCOUNT_TYPE_STRINGS = exports.HUBSPOT_ACCOUNT_TYPES = exports.MIN_HTTP_TIMEOUT = exports.DEFAULT_PORTAL = exports.DEFAULT_ACCOUNT = exports.ALLOW_USAGE_TRACKING = exports.HTTP_USE_LOCALHOST = exports.ENV = exports.HTTP_TIMEOUT = exports.DEFAULT_CMS_PUBLISH_MODE = exports.DEFAULT_ACCOUNT_OVERRIDE_ERROR_ACCOUNT_NOT_FOUND = exports.DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID = exports.DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME = exports.GLOBAL_CONFIG_PATH = exports.HUBSPOT_CONFIGURATION_FILE = exports.HUBSPOT_CONFIGURATION_FOLDER = exports.ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME = exports.DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME = void 0;
6
+ exports.HUBSPOT_ACCOUNT_TYPE_STRINGS = exports.HUBSPOT_ACCOUNT_TYPES = exports.MIN_HTTP_TIMEOUT = exports.DEFAULT_PORTAL = exports.DEFAULT_ACCOUNT = exports.ALLOW_AUTO_UPDATES = exports.AUTO_OPEN_BROWSER = exports.ALLOW_USAGE_TRACKING = exports.HTTP_USE_LOCALHOST = exports.ENV = exports.HTTP_TIMEOUT = exports.DEFAULT_CMS_PUBLISH_MODE = exports.DEFAULT_ACCOUNT_OVERRIDE_ERROR_ACCOUNT_NOT_FOUND = exports.DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID = exports.DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME = exports.STATE_FILE_PATH = exports.GLOBAL_CONFIG_PATH = exports.HUBSPOT_STATE_FILE = exports.HUBSPOT_CONFIGURATION_FILE = exports.HUBSPOT_CONFIGURATION_FOLDER = exports.ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME = exports.DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME = void 0;
7
7
  const lang_1 = require("../utils/lang");
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const os_1 = __importDefault(require("os"));
@@ -11,7 +11,9 @@ exports.DEFAULT_HUBSPOT_CONFIG_YAML_FILE_NAME = 'hubspot.config.yml';
11
11
  exports.ARCHIVED_HUBSPOT_CONFIG_YAML_FILE_NAME = 'archived.hubspot.config.yml';
12
12
  exports.HUBSPOT_CONFIGURATION_FOLDER = '.hscli';
13
13
  exports.HUBSPOT_CONFIGURATION_FILE = 'config.yml';
14
+ exports.HUBSPOT_STATE_FILE = 'state.json';
14
15
  exports.GLOBAL_CONFIG_PATH = path_1.default.join(os_1.default.homedir(), exports.HUBSPOT_CONFIGURATION_FOLDER, exports.HUBSPOT_CONFIGURATION_FILE);
16
+ exports.STATE_FILE_PATH = path_1.default.join(os_1.default.homedir(), exports.HUBSPOT_CONFIGURATION_FOLDER, exports.HUBSPOT_STATE_FILE);
15
17
  exports.DEFAULT_ACCOUNT_OVERRIDE_FILE_NAME = '.hsaccount';
16
18
  exports.DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID = 'DEFAULT_ACCOUNT_OVERRIDE_ERROR_INVALID_ID';
17
19
  exports.DEFAULT_ACCOUNT_OVERRIDE_ERROR_ACCOUNT_NOT_FOUND = 'DEFAULT_ACCOUNT_OVERRIDE_ERROR_ACCOUNT_NOT_FOUND';
@@ -20,6 +22,8 @@ exports.HTTP_TIMEOUT = 'httpTimeout';
20
22
  exports.ENV = 'env';
21
23
  exports.HTTP_USE_LOCALHOST = 'httpUseLocalhost';
22
24
  exports.ALLOW_USAGE_TRACKING = 'allowUsageTracking';
25
+ exports.AUTO_OPEN_BROWSER = 'autoOpenBrowser';
26
+ exports.ALLOW_AUTO_UPDATES = 'allowAutoUpdates';
23
27
  exports.DEFAULT_ACCOUNT = 'defaultAccount';
24
28
  exports.DEFAULT_PORTAL = 'defaultPortal';
25
29
  exports.MIN_HTTP_TIMEOUT = 3000;
package/lang/en.json CHANGED
@@ -78,6 +78,15 @@
78
78
  "invalidPersonalAccessKey": "Error while retrieving new access token: {{ errorMessage }}"
79
79
  }
80
80
  },
81
+ "crm": {
82
+ "importData": {
83
+ "errors": {
84
+ "fileNotFound": "The file {{ fileName }} does not exist",
85
+ "notJson": "You must provide a JSON file for the import data request schema.",
86
+ "noFiles": "You must provide at least one data file for the import data request schema."
87
+ }
88
+ }
89
+ },
81
90
  "cms": {
82
91
  "modules": {
83
92
  "createModule": {
@@ -243,13 +252,13 @@
243
252
  "empty": "The config file was empty. Initializing an empty config."
244
253
  },
245
254
  "validate": {
246
- "noConfig": "Valiation failed: No config was found.",
247
- "noConfigAccounts": "Valiation failed: config.accounts[] is not defined.",
248
- "emptyAccountConfig": "Valiation failed: config.accounts[] has an empty entry.",
249
- "noAccountId": "Valiation failed: config.accounts[] has an entry missing accountId.",
250
- "duplicateAccountIds": "Valiation failed: config.accounts[] has multiple entries with {{ accountId }}.",
251
- "duplicateAccountNames": "Valiation failed: config.accounts[] has multiple entries with {{ accountName }}.",
252
- "nameContainsSpaces": "Valiation failed: config.name {{ accountName }} cannot contain spaces."
255
+ "noConfig": "Validation failed: No config was found.",
256
+ "noConfigAccounts": "Validation failed: config.accounts[] is not defined.",
257
+ "emptyAccountConfig": "Validation failed: config.accounts[] has an empty entry.",
258
+ "noAccountId": "Validation failed: config.accounts[] has an entry missing accountId.",
259
+ "duplicateAccountIds": "Validation failed: config.accounts[] has multiple entries with {{ accountId }}.",
260
+ "duplicateAccountNames": "Validation failed: config.accounts[] has multiple entries with {{ accountName }}.",
261
+ "nameContainsSpaces": "Validation failed: config.name {{ accountName }} cannot contain spaces."
253
262
  },
254
263
  "updateAccount": {
255
264
  "noConfigToUpdate": "No config to update.",
@@ -311,6 +320,26 @@
311
320
  "configUtils": {
312
321
  "unknownType": "Unknown auth type {{ type }}"
313
322
  },
323
+ "state": {
324
+ "ensureCLIDirectory": {
325
+ "errors": {
326
+ "cannotCreateDirectory": "Cannot create CLI state directory: {{ error }}"
327
+ }
328
+ },
329
+ "getCurrentState": {
330
+ "debug": {
331
+ "emptyStateFile": "State file is empty, using default state"
332
+ },
333
+ "errors": {
334
+ "errorReading": "Error reading CLI state, using defaults: {{ error }}"
335
+ }
336
+ },
337
+ "setStateValue": {
338
+ "errors": {
339
+ "failedToWrite": "Failed to write CLI state: {{ error }}"
340
+ }
341
+ }
342
+ },
314
343
  "environment": {
315
344
  "loadConfig": {
316
345
  "missingAccountId": "Unable to load config from environment variables: Missing accountId",
@@ -38,6 +38,16 @@ function getFileType(filePath) {
38
38
  return files_1.FILE_TYPES.other;
39
39
  }
40
40
  }
41
+ function isMetaJsonFile(filePath) {
42
+ return path_1.default.basename(filePath).toLowerCase() === 'meta.json';
43
+ }
44
+ function resolveUploadPath(file, fieldsJsPaths, tmpDirRegex, regex, dest) {
45
+ const fieldsJsFileInfo = fieldsJsPaths.find(f => f.outputPath === file);
46
+ const relativePath = file.replace(fieldsJsFileInfo ? tmpDirRegex : regex, '');
47
+ const destPath = (0, path_2.convertToUnixPath)(path_1.default.join(dest, relativePath));
48
+ const originalFilePath = fieldsJsFileInfo ? fieldsJsFileInfo.filePath : file;
49
+ return { fieldsJsFileInfo, relativePath, destPath, originalFilePath };
50
+ }
41
51
  async function getFilesByType(filePaths, projectDir, rootWriteDir, commandOptions) {
42
52
  const { convertFields, fieldOptions } = commandOptions;
43
53
  const projectDirRegex = new RegExp(`^${(0, escapeRegExp_1.escapeRegExp)(projectDir)}`);
@@ -106,6 +116,12 @@ const defaultUploadFinalErrorCallback = (accountId, file, destPath, error) => {
106
116
  payload: file,
107
117
  });
108
118
  };
119
+ async function uploadMetaJsonFiles(moduleFiles, uploadFile) {
120
+ const moduleMetaJsonFiles = moduleFiles.filter(isMetaJsonFile);
121
+ if (moduleMetaJsonFiles.length > 0) {
122
+ await queue.addAll(moduleMetaJsonFiles.map(uploadFile));
123
+ }
124
+ }
109
125
  async function uploadFolder(accountId, src, dest, fileMapperOptions, commandOptions = {}, filePaths = [], cmsPublishMode = null) {
110
126
  const { saveOutput, convertFields, onAttemptCallback, onSuccessCallback, onFirstErrorCallback, onRetryCallback, onFinalErrorCallback, } = commandOptions;
111
127
  const _onAttemptCallback = onAttemptCallback || defaultUploadAttemptCallback;
@@ -120,23 +136,15 @@ async function uploadFolder(accountId, src, dest, fileMapperOptions, commandOpti
120
136
  const apiOptions = (0, fileMapper_1.getFileMapperQueryValues)(cmsPublishMode, fileMapperOptions);
121
137
  const failures = [];
122
138
  let fieldsJsPaths = [];
123
- let tmpDirRegex;
139
+ const tmpDirRegex = new RegExp(`^${(0, escapeRegExp_1.escapeRegExp)(tmpDir || '')}`);
124
140
  const [filesByType, fieldsJsObjects] = await getFilesByType(filePaths, src, tmpDir, commandOptions);
125
- const fileList = Object.values(filesByType);
126
141
  if (fieldsJsObjects.length) {
127
142
  fieldsJsPaths = fieldsJsObjects.map(fieldsJs => {
128
143
  return { outputPath: fieldsJs.outputPath, filePath: fieldsJs.filePath };
129
144
  });
130
- tmpDirRegex = new RegExp(`^${(0, escapeRegExp_1.escapeRegExp)(tmpDir || '')}`);
131
145
  }
132
146
  function uploadFile(file) {
133
- const fieldsJsFileInfo = fieldsJsPaths.find(f => f.outputPath === file);
134
- const originalFilePath = fieldsJsFileInfo
135
- ? fieldsJsFileInfo.filePath
136
- : file;
137
- // files in fieldsJsPaths always belong to the tmp directory.
138
- const relativePath = file.replace(fieldsJsFileInfo ? tmpDirRegex : regex, '');
139
- const destPath = (0, path_2.convertToUnixPath)(path_1.default.join(dest, relativePath));
147
+ const { originalFilePath, destPath } = resolveUploadPath(file, fieldsJsPaths, tmpDirRegex, regex, dest);
140
148
  return async () => {
141
149
  _onAttemptCallback(originalFilePath, destPath);
142
150
  try {
@@ -155,9 +163,23 @@ async function uploadFolder(accountId, src, dest, fileMapperOptions, commandOpti
155
163
  }
156
164
  };
157
165
  }
158
- for (let i = 0; i < fileList.length; i++) {
159
- const filesToUpload = fileList[i];
160
- await queue.addAll(filesToUpload.map(uploadFile));
166
+ // Upload all meta.json files first
167
+ await uploadMetaJsonFiles(filesByType[files_1.FILE_TYPES.module] || [], uploadFile);
168
+ // Collect all remaining files for upload
169
+ const deferredFiles = [];
170
+ Object.entries(filesByType).forEach(([fileType, files]) => {
171
+ if (fileType === files_1.FILE_TYPES.module) {
172
+ // Add non-meta.json module files
173
+ deferredFiles.push(...files.filter(f => !isMetaJsonFile(f)));
174
+ }
175
+ else {
176
+ // Add all non-module files
177
+ deferredFiles.push(...files);
178
+ }
179
+ });
180
+ // Upload all remaining files concurrently
181
+ if (deferredFiles.length > 0) {
182
+ await queue.addAll(deferredFiles.map(uploadFile));
161
183
  }
162
184
  const results = await queue
163
185
  .addAll(failures.map(({ file, destPath }) => {
package/lib/crm.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import { ImportRequest } from '../types/Crm';
2
+ export declare function getImportDataRequest(fileName: string): {
3
+ importRequest: ImportRequest;
4
+ dataFileNames: string[];
5
+ };
6
+ export declare function validateImportRequestFile(fileName: string): void;
package/lib/crm.js ADDED
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.validateImportRequestFile = exports.getImportDataRequest = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const path_2 = require("./path");
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
10
+ const lang_1 = require("../utils/lang");
11
+ function getImportDataRequest(fileName) {
12
+ validateImportRequestFile(fileName);
13
+ const importRequest = fs_extra_1.default.readJsonSync(path_1.default.resolve((0, path_2.getCwd)(), fileName));
14
+ const dataFileNames = importRequest.files.map(file => file.fileName);
15
+ // allow relative paths in the provided import request
16
+ importRequest.files = importRequest.files.map(file => ({
17
+ ...file,
18
+ fileName: path_1.default.basename(file.fileName),
19
+ }));
20
+ if (dataFileNames.length === 0) {
21
+ throw new Error((0, lang_1.i18n)('lib.crm.importData.errors.noFiles'));
22
+ }
23
+ dataFileNames.forEach(fileName => {
24
+ if (!fileExists(fileName)) {
25
+ throw new Error((0, lang_1.i18n)('lib.crm.importData.errors.fileNotFound', { fileName }));
26
+ }
27
+ });
28
+ return { importRequest, dataFileNames };
29
+ }
30
+ exports.getImportDataRequest = getImportDataRequest;
31
+ function validateImportRequestFile(fileName) {
32
+ if (!fileExists(fileName)) {
33
+ throw new Error((0, lang_1.i18n)('lib.crm.importData.errors.fileNotFound', { fileName }));
34
+ }
35
+ if (path_1.default.extname(fileName) !== '.json') {
36
+ throw new Error((0, lang_1.i18n)('lib.crm.importData.errors.notJson'));
37
+ }
38
+ }
39
+ exports.validateImportRequestFile = validateImportRequestFile;
40
+ function fileExists(_path) {
41
+ try {
42
+ const absoluteSrcPath = path_1.default.resolve((0, path_2.getCwd)(), _path);
43
+ if (!absoluteSrcPath)
44
+ return false;
45
+ const stats = fs_extra_1.default.statSync(absoluteSrcPath);
46
+ const isFile = stats.isFile();
47
+ if (!isFile) {
48
+ return false;
49
+ }
50
+ }
51
+ catch (e) {
52
+ return false;
53
+ }
54
+ return true;
55
+ }
package/lib/gitignore.js CHANGED
@@ -18,7 +18,7 @@ function checkAndAddConfigToGitignore(configPath) {
18
18
  return;
19
19
  let gitignoreFilePath = gitignoreFiles && gitignoreFiles.length ? gitignoreFiles[0] : null;
20
20
  if (!gitignoreFilePath) {
21
- gitignoreFilePath = path_1.default.resolve(configPath, GITIGNORE_FILE);
21
+ gitignoreFilePath = path_1.default.join(path_1.default.dirname(configPath), GITIGNORE_FILE);
22
22
  (0, fs_extra_1.writeFileSync)(gitignoreFilePath, '');
23
23
  }
24
24
  const gitignoreContents = (0, fs_extra_1.readFileSync)(gitignoreFilePath).toString();
package/lib/hubdb.d.ts CHANGED
@@ -8,7 +8,7 @@ export declare function createHubDbTable(accountId: number, src: string): Promis
8
8
  tableId: string;
9
9
  rowCount: number;
10
10
  }>;
11
- export declare function updateHubDbTable(accountId: number, tableId: string, src: string): Promise<AxiosResponse<Table, any>>;
11
+ export declare function updateHubDbTable(accountId: number, tableId: string, src: string): Promise<AxiosResponse<Table, any, {}>>;
12
12
  export declare function downloadHubDbTable(accountId: number, tableId: string, dest: string): Promise<{
13
13
  filePath: string;
14
14
  }>;
@@ -0,0 +1 @@
1
+ export declare function isDeepEqual(object1: unknown, object2: unknown, ignoreKeys?: string[]): boolean;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDeepEqual = void 0;
4
+ function isDeepEqual(object1, object2, ignoreKeys) {
5
+ if (object1 === object2) {
6
+ return true;
7
+ }
8
+ if (object1 === null ||
9
+ object2 === null ||
10
+ typeof object1 !== 'object' ||
11
+ typeof object2 !== 'object') {
12
+ return object1 === object2;
13
+ }
14
+ if (typeof object1 !== typeof object2) {
15
+ return false;
16
+ }
17
+ const isArray1 = Array.isArray(object1);
18
+ const isArray2 = Array.isArray(object2);
19
+ if (isArray1 !== isArray2) {
20
+ return false;
21
+ }
22
+ const objKeys1 = Object.keys(object1).filter(key => !ignoreKeys?.includes(key));
23
+ const objKeys2 = Object.keys(object2).filter(key => !ignoreKeys?.includes(key));
24
+ if (objKeys1.length !== objKeys2.length)
25
+ return false;
26
+ for (const key of objKeys1) {
27
+ const value1 = object1[key];
28
+ const value2 = object2[key];
29
+ if (!isDeepEqual(value1, value2, ignoreKeys)) {
30
+ return false;
31
+ }
32
+ }
33
+ return true;
34
+ }
35
+ exports.isDeepEqual = isDeepEqual;
@@ -7,5 +7,6 @@ export declare function stopPortManagerServer(): Promise<void>;
7
7
  export declare function requestPorts(portData: Array<RequestPortsData>): Promise<{
8
8
  [instanceId: string]: number;
9
9
  }>;
10
+ export declare function getServerPortByInstanceId(serverInstanceId: string): Promise<number>;
10
11
  export declare function deleteServerInstance(serverInstanceId: string): Promise<void>;
11
12
  export declare function portManagerHasActiveServers(): Promise<boolean>;
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.portManagerHasActiveServers = exports.deleteServerInstance = exports.requestPorts = exports.stopPortManagerServer = exports.startPortManagerServer = exports.isPortManagerServerRunning = exports.isPortManagerPortAvailable = exports.BASE_URL = void 0;
6
+ exports.portManagerHasActiveServers = exports.deleteServerInstance = exports.getServerPortByInstanceId = exports.requestPorts = exports.stopPortManagerServer = exports.startPortManagerServer = exports.isPortManagerServerRunning = exports.isPortManagerPortAvailable = exports.BASE_URL = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const PortManagerServer_1 = require("../utils/PortManagerServer");
9
9
  const ports_1 = require("../constants/ports");
@@ -46,6 +46,11 @@ async function requestPorts(portData) {
46
46
  return data.ports;
47
47
  }
48
48
  exports.requestPorts = requestPorts;
49
+ async function getServerPortByInstanceId(serverInstanceId) {
50
+ const { data } = await axios_1.default.get(`${exports.BASE_URL}/servers/${serverInstanceId}`);
51
+ return data.port;
52
+ }
53
+ exports.getServerPortByInstanceId = getServerPortByInstanceId;
49
54
  async function deleteServerInstance(serverInstanceId) {
50
55
  await axios_1.default.delete(`${exports.BASE_URL}/servers/${serverInstanceId}`);
51
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/local-dev-lib",
3
- "version": "0.4.1-experimental.0",
3
+ "version": "0.4.3-experimental.0",
4
4
  "description": "Provides library functionality for HubSpot local development tooling, including the HubSpot CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -20,6 +20,7 @@
20
20
  },
21
21
  "license": "Apache-2.0",
22
22
  "devDependencies": {
23
+ "@hubspot/npm-scripts": "0.0.4",
23
24
  "@inquirer/prompts": "^7.0.1",
24
25
  "@types/content-disposition": "^0.5.5",
25
26
  "@types/cors": "^2.8.15",
@@ -51,6 +52,7 @@
51
52
  "./http/*": "./http/*.js",
52
53
  "./config/getAccountIdentifier": "./config/getAccountIdentifier.js",
53
54
  "./config/migrate": "./config/migrate.js",
55
+ "./config/state": "./config/state.js",
54
56
  "./config": "./config/index.js",
55
57
  "./constants/*": "./constants/*.js",
56
58
  "./models/*": "./models/*.js",
@@ -61,7 +63,7 @@
61
63
  },
62
64
  "dependencies": {
63
65
  "address": "2.0.2",
64
- "axios": "1.8.4",
66
+ "axios": "1.12.0",
65
67
  "chalk": "2.4.2",
66
68
  "chokidar": "3.6.0",
67
69
  "content-disposition": "0.5.4",
@@ -70,6 +72,7 @@
70
72
  "express": "4.21.2",
71
73
  "extract-zip": "2.0.1",
72
74
  "findup-sync": "5.0.0",
75
+ "form-data": "^4.0.4",
73
76
  "fs-extra": "11.2.0",
74
77
  "ignore": "5.3.1",
75
78
  "js-yaml": "4.1.0",
package/types/Build.d.ts CHANGED
@@ -31,6 +31,7 @@ export type Build = {
31
31
  subbuildStatuses: Array<SubbuildStatus>;
32
32
  uploadMessage: string;
33
33
  autoDeployId: number;
34
+ platformVersion: string;
34
35
  };
35
36
  export type FetchProjectBuildsResponse = {
36
37
  results: Array<Build>;
package/types/Config.d.ts CHANGED
@@ -3,7 +3,7 @@ import { CLIAccount_NEW, CLIAccount_DEPRECATED } from './Accounts';
3
3
  import { CmsPublishMode } from './Files';
4
4
  import { ValueOf } from './Utils';
5
5
  export interface CLIConfig_NEW {
6
- accounts: Array<CLIAccount_NEW>;
6
+ accounts?: Array<CLIAccount_NEW>;
7
7
  allowUsageTracking?: boolean;
8
8
  allowAutoUpdates?: boolean;
9
9
  defaultAccount?: string | number;
@@ -44,3 +44,6 @@ export type GitInclusionResult = {
44
44
  configIgnored: boolean;
45
45
  gitignoreFiles: Array<string>;
46
46
  };
47
+ export type HubSpotState = {
48
+ mcpTotalToolCalls: number;
49
+ };
package/types/Crm.d.ts ADDED
@@ -0,0 +1,26 @@
1
+ export interface ImportRequest {
2
+ name: string;
3
+ importOperations: {
4
+ [objectTypeId: string]: 'CREATE' | 'UPDATE' | 'UPSERT';
5
+ };
6
+ dateFormat?: string;
7
+ marketableContactImport?: boolean;
8
+ createContactListFromImport?: boolean;
9
+ files: Array<{
10
+ fileName: string;
11
+ fileFormat: 'CSV' | 'XLSX' | 'XLS';
12
+ fileImportPage: {
13
+ hasHeader: boolean;
14
+ columnMappings: Array<{
15
+ columnObjectTypeId: string;
16
+ columnName: string;
17
+ propertyName: string;
18
+ columnType?: string;
19
+ }>;
20
+ };
21
+ }>;
22
+ }
23
+ export interface ImportResponse {
24
+ id: string;
25
+ state: 'STARTED' | 'PROCESSING' | 'DONE' | 'FAILED' | 'CANCELED' | 'DEFERRED';
26
+ }
package/types/Crm.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/types/Deploy.d.ts CHANGED
@@ -42,7 +42,7 @@ export type ProjectDeployResponseQueued = {
42
42
  status: string;
43
43
  };
44
44
  };
45
- type SubdeployValidationIssue = {
45
+ export type SubdeployValidationIssue = {
46
46
  uid: string;
47
47
  componentTypeName: string;
48
48
  errorMessages: string[];
@@ -56,4 +56,3 @@ export type ProjectDeployResponseBlocked = {
56
56
  issues: SubdeployValidationIssue[];
57
57
  };
58
58
  export type ProjectDeployResponse = ProjectDeployResponseQueued | ProjectDeployResponseBlocked;
59
- export {};
package/utils/accounts.js CHANGED
@@ -5,10 +5,10 @@ function getAccounts(config) {
5
5
  if (!config) {
6
6
  return [];
7
7
  }
8
- else if (Object.hasOwn(config, 'portals')) {
8
+ else if ('portals' in config && Array.isArray(config.portals)) {
9
9
  return config.portals;
10
10
  }
11
- else if (Object.hasOwn(config, 'accounts')) {
11
+ else if ('accounts' in config && Array.isArray(config.accounts)) {
12
12
  return config.accounts;
13
13
  }
14
14
  return [];