@hubspot/local-dev-lib 0.3.10 → 0.3.12

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.
@@ -1,5 +1,7 @@
1
1
  import { Environment } from '../types/Config';
2
2
  import { ScopeData } from '../types/Accounts';
3
+ import { HUBSPOT_ACCOUNT_TYPES } from '../constants/config';
4
+ import { ValueOf } from '../types/Utils';
3
5
  type AccessTokenResponse = {
4
6
  hubId: number;
5
7
  userId: number;
@@ -11,6 +13,7 @@ type AccessTokenResponse = {
11
13
  scopeGroups: Array<string>;
12
14
  encodedOAuthRefreshToken: string;
13
15
  hubName: string;
16
+ accountType: ValueOf<typeof HUBSPOT_ACCOUNT_TYPES>;
14
17
  };
15
18
  export declare function fetchAccessToken(personalAccessKey: string, env?: Environment, portalId?: number): Promise<AccessTokenResponse>;
16
19
  export declare function fetchScopeData(accountId: number, scopeGroup: string): Promise<ScopeData>;
@@ -580,10 +580,13 @@ function getConfigVariablesFromEnv() {
580
580
  personalAccessKey: env[environments_1.ENVIRONMENT_VARIABLES.HUBSPOT_PERSONAL_ACCESS_KEY],
581
581
  portalId: parseInt(env[environments_1.ENVIRONMENT_VARIABLES.HUBSPOT_PORTAL_ID] || '', 10),
582
582
  refreshToken: env[environments_1.ENVIRONMENT_VARIABLES.HUBSPOT_REFRESH_TOKEN],
583
+ httpTimeout: env[environments_1.ENVIRONMENT_VARIABLES.HTTP_TIMEOUT]
584
+ ? parseInt(env[environments_1.ENVIRONMENT_VARIABLES.HTTP_TIMEOUT])
585
+ : undefined,
583
586
  env: (0, environment_1.getValidEnv)(env[environments_1.ENVIRONMENT_VARIABLES.HUBSPOT_ENVIRONMENT]),
584
587
  };
585
588
  }
586
- function generatePersonalAccessKeyConfig(portalId, personalAccessKey, env) {
589
+ function generatePersonalAccessKeyConfig(portalId, personalAccessKey, env, httpTimeout) {
587
590
  return {
588
591
  portals: [
589
592
  {
@@ -593,9 +596,10 @@ function generatePersonalAccessKeyConfig(portalId, personalAccessKey, env) {
593
596
  env,
594
597
  },
595
598
  ],
599
+ httpTimeout,
596
600
  };
597
601
  }
598
- function generateOauthConfig(portalId, clientId, clientSecret, refreshToken, scopes, env) {
602
+ function generateOauthConfig(portalId, clientId, clientSecret, refreshToken, scopes, env, httpTimeout) {
599
603
  return {
600
604
  portals: [
601
605
  {
@@ -612,6 +616,7 @@ function generateOauthConfig(portalId, clientId, clientSecret, refreshToken, sco
612
616
  env,
613
617
  },
614
618
  ],
619
+ httpTimeout,
615
620
  };
616
621
  }
617
622
  function generateApiKeyConfig(portalId, apiKey, env) {
@@ -627,17 +632,20 @@ function generateApiKeyConfig(portalId, apiKey, env) {
627
632
  };
628
633
  }
629
634
  function loadConfigFromEnvironment({ useEnv = false, } = {}) {
630
- const { apiKey, clientId, clientSecret, personalAccessKey, portalId, refreshToken, env, } = getConfigVariablesFromEnv();
635
+ const { apiKey, clientId, clientSecret, personalAccessKey, portalId, refreshToken, env, httpTimeout, } = getConfigVariablesFromEnv();
631
636
  const unableToLoadEnvConfigError = 'Unable to load config from environment variables.';
632
637
  if (!portalId) {
633
638
  useEnv && logger_1.logger.error(unableToLoadEnvConfigError);
634
639
  return;
635
640
  }
641
+ if (httpTimeout && httpTimeout < config_1.MIN_HTTP_TIMEOUT) {
642
+ throw new Error(`The HTTP timeout value ${httpTimeout} is invalid. The value must be a number greater than ${config_1.MIN_HTTP_TIMEOUT}.`);
643
+ }
636
644
  if (personalAccessKey) {
637
- return generatePersonalAccessKeyConfig(portalId, personalAccessKey, env);
645
+ return generatePersonalAccessKeyConfig(portalId, personalAccessKey, env, httpTimeout);
638
646
  }
639
647
  else if (clientId && clientSecret && refreshToken) {
640
- return generateOauthConfig(portalId, clientId, clientSecret, refreshToken, auth_1.OAUTH_SCOPES.map(scope => scope.value), env);
648
+ return generateOauthConfig(portalId, clientId, clientSecret, refreshToken, auth_1.OAUTH_SCOPES.map(scope => scope.value), env, httpTimeout);
641
649
  }
642
650
  else if (apiKey) {
643
651
  return generateApiKeyConfig(portalId, apiKey, env);
@@ -11,4 +11,5 @@ export declare const ENVIRONMENT_VARIABLES: {
11
11
  readonly HUBSPOT_PORTAL_ID: "HUBSPOT_PORTAL_ID";
12
12
  readonly HUBSPOT_REFRESH_TOKEN: "HUBSPOT_REFRESH_TOKEN";
13
13
  readonly HUBSPOT_ENVIRONMENT: "HUBSPOT_ENVIRONMENT";
14
+ readonly HTTP_TIMEOUT: "HTTP_TIMEOUT";
14
15
  };
@@ -14,4 +14,5 @@ exports.ENVIRONMENT_VARIABLES = {
14
14
  HUBSPOT_PORTAL_ID: 'HUBSPOT_PORTAL_ID',
15
15
  HUBSPOT_REFRESH_TOKEN: 'HUBSPOT_REFRESH_TOKEN',
16
16
  HUBSPOT_ENVIRONMENT: 'HUBSPOT_ENVIRONMENT',
17
+ HTTP_TIMEOUT: 'HTTP_TIMEOUT',
17
18
  };
@@ -1,21 +1,24 @@
1
1
  import { AxiosError } from 'axios';
2
- import { GenericError, AxiosErrorContext } from '../types/Error';
2
+ import { GenericError, AxiosErrorContext, ValidationError } from '../types/Error';
3
3
  import { HubSpotAuthError } from '../models/HubSpotAuthError';
4
- export declare function isSpecifiedError(err: Error | AxiosError, { statusCode, category, subCategory, }: {
4
+ export declare function isSpecifiedError(err: Error | AxiosError, { statusCode, category, subCategory, code, }: {
5
5
  statusCode?: number;
6
6
  category?: string;
7
7
  subCategory?: string;
8
+ code?: string;
8
9
  }): boolean;
9
10
  export declare function isMissingScopeError(err: Error | AxiosError): boolean;
10
11
  export declare function isGatingError(err: Error | AxiosError): boolean;
12
+ export declare function isTimeoutError(err: Error | AxiosError): boolean;
11
13
  export declare function isApiUploadValidationError(err: AxiosError<any>): boolean;
12
14
  export declare function isSpecifiedHubSpotAuthError(err: GenericError, { status, category, subCategory }: Partial<HubSpotAuthError>): boolean;
15
+ export declare function parseValidationErrors(responseData?: {
16
+ errors?: Array<ValidationError>;
17
+ message?: string;
18
+ }): Array<string>;
13
19
  export declare function getAxiosErrorWithContext(error: AxiosError<any>, context?: AxiosErrorContext): Error;
14
20
  /**
15
21
  * @throws
16
22
  */
17
23
  export declare function throwApiError(error: AxiosError, context?: AxiosErrorContext): never;
18
- /**
19
- * @throws
20
- */
21
24
  export declare function throwApiUploadError(error: AxiosError, context?: AxiosErrorContext): never;
@@ -1,17 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.throwApiUploadError = exports.throwApiError = exports.getAxiosErrorWithContext = exports.isSpecifiedHubSpotAuthError = exports.isApiUploadValidationError = exports.isGatingError = exports.isMissingScopeError = exports.isSpecifiedError = void 0;
3
+ exports.throwApiUploadError = exports.throwApiError = exports.getAxiosErrorWithContext = exports.parseValidationErrors = exports.isSpecifiedHubSpotAuthError = exports.isApiUploadValidationError = exports.isTimeoutError = exports.isGatingError = exports.isMissingScopeError = exports.isSpecifiedError = void 0;
4
4
  const api_1 = require("../constants/api");
5
5
  const lang_1 = require("../utils/lang");
6
6
  const standardErrors_1 = require("./standardErrors");
7
7
  const i18nKey = 'errors.apiErrors';
8
- function isSpecifiedError(err, { statusCode, category, subCategory, }) {
8
+ function isSpecifiedError(err, { statusCode, category, subCategory, code, }) {
9
9
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
10
10
  const error = (err && err.cause) || err;
11
11
  const statusCodeErr = !statusCode || error.response?.status === statusCode;
12
12
  const categoryErr = !category || error.response?.data?.category === category;
13
13
  const subCategoryErr = !subCategory || error.response?.data?.subCategory === subCategory;
14
- return error.isAxiosError && statusCodeErr && categoryErr && subCategoryErr;
14
+ const codeError = !code || error.code === code;
15
+ return (error.isAxiosError &&
16
+ statusCodeErr &&
17
+ categoryErr &&
18
+ subCategoryErr &&
19
+ codeError);
15
20
  }
16
21
  exports.isSpecifiedError = isSpecifiedError;
17
22
  function isMissingScopeError(err) {
@@ -22,6 +27,10 @@ function isGatingError(err) {
22
27
  return isSpecifiedError(err, { statusCode: 403, category: 'GATED' });
23
28
  }
24
29
  exports.isGatingError = isGatingError;
30
+ function isTimeoutError(err) {
31
+ return isSpecifiedError(err, { code: 'ETIMEDOUT' });
32
+ }
33
+ exports.isTimeoutError = isTimeoutError;
25
34
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
35
  function isApiUploadValidationError(err) {
27
36
  return (err.isAxiosError &&
@@ -58,14 +67,15 @@ function parseValidationErrors(responseData = { errors: [], message: '' }) {
58
67
  }
59
68
  return errorMessages;
60
69
  }
70
+ exports.parseValidationErrors = parseValidationErrors;
61
71
  /**
62
72
  * @throws
63
73
  */
64
74
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
65
- function throwValidationErrors(error) {
75
+ function throwValidationError(error) {
66
76
  const validationErrorMessages = parseValidationErrors(error?.response?.data);
67
77
  if (validationErrorMessages.length) {
68
- (0, standardErrors_1.throwError)(new Error(validationErrorMessages.join(' '), { cause: error }));
78
+ return new Error(validationErrorMessages.join(' '), { cause: error });
69
79
  }
70
80
  }
71
81
  function getAxiosErrorWithContext(
@@ -165,12 +175,9 @@ function throwApiError(error, context = {}) {
165
175
  (0, standardErrors_1.throwError)(error);
166
176
  }
167
177
  exports.throwApiError = throwApiError;
168
- /**
169
- * @throws
170
- */
171
178
  function throwApiUploadError(error, context = {}) {
172
179
  if (isApiUploadValidationError(error)) {
173
- throwValidationErrors(error);
180
+ throwValidationError(error);
174
181
  }
175
182
  throwApiError(error, context);
176
183
  }
@@ -7,6 +7,9 @@ const urls_1 = require("../lib/urls");
7
7
  exports.DEFAULT_USER_AGENT_HEADERS = {
8
8
  'User-Agent': `HubSpot Local Dev Lib/${package_json_1.version}`,
9
9
  };
10
+ const DEFAULT_TRANSITIONAL = {
11
+ clarifyTimeoutError: true,
12
+ };
10
13
  function getAxiosConfig(options) {
11
14
  const { env, localHostOverride, headers, ...rest } = options;
12
15
  const { httpTimeout, httpUseLocalhost } = (0, config_1.getAndLoadConfigIfNeeded)();
@@ -17,6 +20,7 @@ function getAxiosConfig(options) {
17
20
  ...(headers || {}),
18
21
  },
19
22
  timeout: httpTimeout || 15000,
23
+ transitional: DEFAULT_TRANSITIONAL,
20
24
  ...rest,
21
25
  };
22
26
  }
package/lib/fileMapper.js CHANGED
@@ -15,6 +15,7 @@ const standardErrors_1 = require("../errors/standardErrors");
15
15
  const extensions_1 = require("../constants/extensions");
16
16
  const files_1 = require("../constants/files");
17
17
  const fileSystemErrors_1 = require("../errors/fileSystemErrors");
18
+ const apiErrors_1 = require("../errors/apiErrors");
18
19
  const lang_1 = require("../utils/lang");
19
20
  const i18nKey = 'lib.fileMapper';
20
21
  const queue = new p_queue_1.default({
@@ -196,9 +197,6 @@ async function writeFileMapperNode(accountId, filepath, node, mode, options = {}
196
197
  }
197
198
  return true;
198
199
  }
199
- function isTimeout(err) {
200
- return !!err && (err.status === 408 || err.code === 'ESOCKETTIMEDOUT');
201
- }
202
200
  async function downloadFile(accountId, src, destPath, mode, options = {}) {
203
201
  const { isFile, isHubspot } = getTypeDataFromPath(src);
204
202
  try {
@@ -234,7 +232,7 @@ async function downloadFile(accountId, src, destPath, mode, options = {}) {
234
232
  }
235
233
  catch (err) {
236
234
  const error = err;
237
- if (isHubspot && isTimeout(error)) {
235
+ if (isHubspot && (0, apiErrors_1.isTimeoutError)(error)) {
238
236
  (0, standardErrors_1.throwErrorWithMessage)(`${i18nKey}.errors.assetTimeout`, {}, error);
239
237
  }
240
238
  else {
@@ -249,24 +247,13 @@ async function fetchFolderFromApi(accountId, src, mode, options = {}) {
249
247
  src,
250
248
  });
251
249
  }
252
- try {
253
- const srcPath = isRoot ? '@root' : src;
254
- const queryValues = getFileMapperQueryValues(mode, options);
255
- const node = isHubspot
256
- ? await (0, fileMapper_1.downloadDefault)(accountId, srcPath, queryValues)
257
- : await (0, fileMapper_1.download)(accountId, srcPath, queryValues);
258
- logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.folderFetch`, { src, accountId }));
259
- return node;
260
- }
261
- catch (err) {
262
- const error = err;
263
- if (isHubspot && isTimeout(error)) {
264
- (0, standardErrors_1.throwErrorWithMessage)(`${i18nKey}.errors.assetTimeout`, {}, error);
265
- }
266
- else {
267
- (0, standardErrors_1.throwError)(error);
268
- }
269
- }
250
+ const srcPath = isRoot ? '@root' : src;
251
+ const queryValues = getFileMapperQueryValues(mode, options);
252
+ const node = isHubspot
253
+ ? await (0, fileMapper_1.downloadDefault)(accountId, srcPath, queryValues)
254
+ : await (0, fileMapper_1.download)(accountId, srcPath, queryValues);
255
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.folderFetch`, { src, accountId }));
256
+ return node;
270
257
  }
271
258
  exports.fetchFolderFromApi = fetchFolderFromApi;
272
259
  async function downloadFolder(accountId, src, destPath, mode, options = {}) {
@@ -302,7 +289,13 @@ async function downloadFolder(accountId, src, destPath, mode, options = {}) {
302
289
  }
303
290
  }
304
291
  catch (err) {
305
- (0, standardErrors_1.throwErrorWithMessage)(`${i18nKey}.errors.failedToFetchFolder`, { src, dest: destPath }, err);
292
+ const error = err;
293
+ if ((0, apiErrors_1.isTimeoutError)(error)) {
294
+ (0, standardErrors_1.throwErrorWithMessage)(`${i18nKey}.errors.assetTimeout`, {}, error);
295
+ }
296
+ else {
297
+ (0, standardErrors_1.throwErrorWithMessage)(`${i18nKey}.errors.failedToFetchFolder`, { src, dest: destPath }, err);
298
+ }
306
299
  }
307
300
  }
308
301
  /**
@@ -1,5 +1,7 @@
1
1
  import { CLIAccount } from '../types/Accounts';
2
2
  import { Environment } from '../types/Config';
3
+ import { HUBSPOT_ACCOUNT_TYPES } from '../constants/config';
4
+ import { ValueOf } from '../types/Utils';
3
5
  type AccessToken = {
4
6
  portalId: number;
5
7
  accessToken: string;
@@ -10,6 +12,7 @@ type AccessToken = {
10
12
  };
11
13
  encodedOAuthRefreshToken: string;
12
14
  hubName: string;
15
+ accountType: ValueOf<typeof HUBSPOT_ACCOUNT_TYPES>;
13
16
  };
14
17
  export declare function getAccessToken(personalAccessKey: string, env?: Environment, accountId?: number): Promise<AccessToken>;
15
18
  export declare function accessTokenForPersonalAccessKey(accountId: number): Promise<string | undefined>;
@@ -13,6 +13,8 @@ const sandboxHubs_1 = require("../api/sandboxHubs");
13
13
  const config_1 = require("../config");
14
14
  const config_2 = require("../constants/config");
15
15
  const developerTestAccounts_1 = require("../api/developerTestAccounts");
16
+ const logger_1 = require("./logging/logger");
17
+ const apiErrors_1 = require("../errors/apiErrors");
16
18
  const i18nKey = 'lib.personalAccessKey';
17
19
  const refreshRequests = new Map();
18
20
  function getRefreshKey(personalAccessKey, expiration) {
@@ -40,6 +42,7 @@ async function getAccessToken(personalAccessKey, env = environments_1.ENVIRONMEN
40
42
  enabledFeatures: response.enabledFeatures,
41
43
  encodedOAuthRefreshToken: response.encodedOAuthRefreshToken,
42
44
  hubName: response.hubName,
45
+ accountType: response.accountType,
43
46
  };
44
47
  }
45
48
  exports.getAccessToken = getAccessToken;
@@ -107,50 +110,33 @@ async function enabledFeaturesForPersonalAccessKey(accountId) {
107
110
  }
108
111
  exports.enabledFeaturesForPersonalAccessKey = enabledFeaturesForPersonalAccessKey;
109
112
  async function updateConfigWithAccessToken(token, personalAccessKey, env, name, makeDefault = false) {
110
- const { portalId, accessToken, expiresAt } = token;
113
+ const { portalId, accessToken, expiresAt, accountType } = token;
111
114
  const accountEnv = env || (0, config_1.getEnv)(name);
112
- let accountType = config_2.HUBSPOT_ACCOUNT_TYPES.STANDARD;
113
- let sandboxAccountType = null;
114
115
  let parentAccountId;
115
116
  try {
116
- const sandboxDataResponse = await (0, sandboxHubs_1.fetchSandboxHubData)(accessToken, portalId, accountEnv);
117
- if (sandboxDataResponse) {
118
- const hubType = sandboxDataResponse.type
119
- ? sandboxDataResponse.type.toUpperCase()
120
- : null;
121
- switch (hubType) {
122
- case 'DEVELOPER':
123
- accountType = config_2.HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX;
124
- sandboxAccountType = 'DEVELOPER';
125
- break;
126
- case 'STANDARD':
127
- accountType = config_2.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX;
128
- sandboxAccountType = 'STANDARD';
129
- break;
130
- default:
131
- accountType = config_2.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX;
132
- sandboxAccountType = 'STANDARD';
133
- break;
134
- }
117
+ if (accountType === config_2.HUBSPOT_ACCOUNT_TYPES.STANDARD_SANDBOX ||
118
+ accountType === config_2.HUBSPOT_ACCOUNT_TYPES.DEVELOPMENT_SANDBOX) {
119
+ const sandboxDataResponse = await (0, sandboxHubs_1.fetchSandboxHubData)(accessToken, portalId, accountEnv);
135
120
  if (sandboxDataResponse.parentHubId) {
136
121
  parentAccountId = sandboxDataResponse.parentHubId;
137
122
  }
138
123
  }
139
124
  }
140
125
  catch (err) {
141
- // Ignore error, returns 404 if account is not a sandbox
126
+ // Log error but do not throw
127
+ logger_1.logger.debug((0, apiErrors_1.getAxiosErrorWithContext)(err).message);
142
128
  }
143
129
  try {
144
- if (accountType === config_2.HUBSPOT_ACCOUNT_TYPES.STANDARD) {
130
+ if (accountType === config_2.HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST) {
145
131
  const developerTestAccountResponse = await (0, developerTestAccounts_1.fetchDeveloperTestAccountData)(accessToken, portalId, accountEnv);
146
132
  if (developerTestAccountResponse) {
147
- accountType = config_2.HUBSPOT_ACCOUNT_TYPES.DEVELOPER_TEST;
148
133
  parentAccountId = developerTestAccountResponse.parentPortalId;
149
134
  }
150
135
  }
151
136
  }
152
137
  catch (err) {
153
- // Ignore error, returns 404 if account is not a test account
138
+ // Log error but do not throw
139
+ logger_1.logger.debug((0, apiErrors_1.getAxiosErrorWithContext)(err).message);
154
140
  }
155
141
  const updatedConfig = (0, config_1.updateAccountConfig)({
156
142
  accountId: portalId,
@@ -159,7 +145,6 @@ async function updateConfigWithAccessToken(token, personalAccessKey, env, name,
159
145
  name,
160
146
  authType: auth_1.PERSONAL_ACCESS_KEY_AUTH_METHOD.value,
161
147
  tokenInfo: { accessToken, expiresAt },
162
- sandboxAccountType,
163
148
  parentAccountId,
164
149
  env: accountEnv,
165
150
  });
package/lib/urls.js CHANGED
@@ -11,7 +11,11 @@ function getEnvUrlString(env) {
11
11
  const getHubSpotWebsiteOrigin = (env) => `https://app.hubspot${getEnvUrlString(env)}.com`;
12
12
  exports.getHubSpotWebsiteOrigin = getHubSpotWebsiteOrigin;
13
13
  function getHubSpotApiOrigin(env, useLocalHost) {
14
- let domain = process.env.HUBAPI_DOMAIN_OVERRIDE;
14
+ let domain;
15
+ const domainOverride = process.env.HUBAPI_DOMAIN_OVERRIDE;
16
+ if (domainOverride && typeof domainOverride === 'string') {
17
+ domain = `${domainOverride}${getEnvUrlString(env)}`;
18
+ }
15
19
  if (!domain || typeof domain !== 'string') {
16
20
  domain = `${useLocalHost ? 'local' : 'api'}.hubapi${getEnvUrlString(env)}`;
17
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hubspot/local-dev-lib",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "Provides library functionality for HubSpot local development tooling, including the HubSpot CLI",
5
5
  "main": "lib/index.js",
6
6
  "repository": {