@hubspot/local-dev-lib 0.4.0-experimental.1 → 0.4.2-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 +2 -0
- package/api/appsDev.js +22 -1
- package/api/crm.d.ts +3 -0
- package/api/crm.js +29 -0
- package/api/developerTestAccounts.d.ts +7 -8
- package/api/developerTestAccounts.js +38 -5
- package/api/github.js +28 -22
- package/api/localDevAuth.d.ts +1 -1
- package/api/projects.d.ts +1 -1
- package/api/projects.js +3 -1
- package/api/sandboxHubs.d.ts +3 -1
- package/api/sandboxHubs.js +18 -1
- package/config/CLIConfiguration.d.ts +4 -0
- package/config/CLIConfiguration.js +34 -0
- package/config/config_DEPRECATED.d.ts +7 -1
- package/config/config_DEPRECATED.js +41 -8
- package/config/index.d.ts +5 -1
- package/config/index.js +38 -4
- package/config/migrate.js +6 -0
- package/errors/index.d.ts +1 -0
- package/errors/index.js +10 -1
- package/lang/en.json +22 -7
- package/lib/archive.d.ts +1 -1
- package/lib/archive.js +63 -6
- package/lib/cms/uploadFolder.js +35 -13
- package/lib/crm.d.ts +6 -0
- package/lib/crm.js +55 -0
- package/lib/github.js +14 -1
- package/lib/hubdb.d.ts +1 -1
- package/lib/isDeepEqual.d.ts +1 -0
- package/lib/isDeepEqual.js +35 -0
- package/package.json +4 -2
- package/types/Archive.d.ts +7 -1
- package/types/Config.d.ts +4 -0
- package/types/Crm.d.ts +26 -0
- package/types/Crm.js +2 -0
- package/types/Deploy.d.ts +16 -1
- package/types/Github.d.ts +3 -1
- package/types/Sandbox.d.ts +33 -0
- package/types/Sandbox.js +10 -0
- package/types/developerTestAccounts.d.ts +29 -0
package/errors/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isFileSystemError = exports.isSystemError = exports.isHubSpotHttpError = exports.isValidationError = exports.isAuthError = exports.isTimeoutError = exports.isGatingError = exports.isMissingScopeError = exports.isSpecifiedError = void 0;
|
|
3
|
+
exports.isFileSystemError = exports.isSystemError = exports.isGithubRateLimitError = exports.isHubSpotHttpError = exports.isValidationError = exports.isAuthError = exports.isTimeoutError = exports.isGatingError = exports.isMissingScopeError = exports.isSpecifiedError = void 0;
|
|
4
4
|
const HubSpotHttpError_1 = require("../models/HubSpotHttpError");
|
|
5
5
|
const FileSystemError_1 = require("../models/FileSystemError");
|
|
6
6
|
function isSpecifiedError(err, { statusCode, category, subCategory, errorType, code, }) {
|
|
@@ -47,6 +47,15 @@ function isHubSpotHttpError(error) {
|
|
|
47
47
|
return !!error && error instanceof HubSpotHttpError_1.HubSpotHttpError;
|
|
48
48
|
}
|
|
49
49
|
exports.isHubSpotHttpError = isHubSpotHttpError;
|
|
50
|
+
function isGithubRateLimitError(err) {
|
|
51
|
+
if (!isHubSpotHttpError(err)) {
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return (!!err.headers &&
|
|
55
|
+
err.headers['x-ratelimit-remaining'] === '0' &&
|
|
56
|
+
'x-github-request-id' in err.headers);
|
|
57
|
+
}
|
|
58
|
+
exports.isGithubRateLimitError = isGithubRateLimitError;
|
|
50
59
|
function isSystemError(err) {
|
|
51
60
|
return (err instanceof Error &&
|
|
52
61
|
'errno' in err &&
|
package/lang/en.json
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
}
|
|
32
32
|
},
|
|
33
33
|
"github": {
|
|
34
|
+
"rateLimitError": "Github rate limit hit. Set the GITHUB_TOKEN env variable with your github PATH. This will increase the github api's rate limit.",
|
|
34
35
|
"fetchFileFromRepository": {
|
|
35
36
|
"fetching": "Fetching {{ path }}...",
|
|
36
37
|
"errors": {
|
|
@@ -77,6 +78,15 @@
|
|
|
77
78
|
"invalidPersonalAccessKey": "Error while retrieving new access token: {{ errorMessage }}"
|
|
78
79
|
}
|
|
79
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
|
+
},
|
|
80
90
|
"cms": {
|
|
81
91
|
"modules": {
|
|
82
92
|
"createModule": {
|
|
@@ -242,13 +252,13 @@
|
|
|
242
252
|
"empty": "The config file was empty. Initializing an empty config."
|
|
243
253
|
},
|
|
244
254
|
"validate": {
|
|
245
|
-
"noConfig": "
|
|
246
|
-
"noConfigAccounts": "
|
|
247
|
-
"emptyAccountConfig": "
|
|
248
|
-
"noAccountId": "
|
|
249
|
-
"duplicateAccountIds": "
|
|
250
|
-
"duplicateAccountNames": "
|
|
251
|
-
"nameContainsSpaces": "
|
|
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."
|
|
252
262
|
},
|
|
253
263
|
"updateAccount": {
|
|
254
264
|
"noConfigToUpdate": "No config to update.",
|
|
@@ -292,6 +302,11 @@
|
|
|
292
302
|
"errors": {
|
|
293
303
|
"invalidInput": "Unable to update allowUsageTracking. The value {{ isEnabled }} is invalid. The value must be a boolean."
|
|
294
304
|
}
|
|
305
|
+
},
|
|
306
|
+
"updateAutoOpenBrowser": {
|
|
307
|
+
"errors": {
|
|
308
|
+
"invalidInput": "Unable to update autoOpenBrowser. The value {{ isEnabled }} is invalid. The value must be a boolean."
|
|
309
|
+
}
|
|
295
310
|
}
|
|
296
311
|
},
|
|
297
312
|
"configFile": {
|
package/lib/archive.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { CopySourceToDestOptions } from '../types/Archive';
|
|
4
|
-
export declare function extractZipArchive(zip: Buffer, name: string, dest: string, { sourceDir, includesRootDir, hideLogs }?: CopySourceToDestOptions): Promise<boolean>;
|
|
4
|
+
export declare function extractZipArchive(zip: Buffer, name: string, dest: string, { sourceDir, includesRootDir, hideLogs, handleCollision, }?: CopySourceToDestOptions): Promise<boolean>;
|
package/lib/archive.js
CHANGED
|
@@ -1,16 +1,40 @@
|
|
|
1
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
|
+
};
|
|
2
25
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
26
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
27
|
};
|
|
5
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
29
|
exports.extractZipArchive = void 0;
|
|
7
30
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
-
const path_1 = require("path");
|
|
31
|
+
const path_1 = __importStar(require("path"));
|
|
9
32
|
const os_1 = require("os");
|
|
10
33
|
const extract_zip_1 = __importDefault(require("extract-zip"));
|
|
11
34
|
const logger_1 = require("./logger");
|
|
12
35
|
const lang_1 = require("../utils/lang");
|
|
13
36
|
const FileSystemError_1 = require("../models/FileSystemError");
|
|
37
|
+
const fs_1 = require("./fs");
|
|
14
38
|
const i18nKey = 'lib.archive';
|
|
15
39
|
async function extractZip(name, zip, hideLogs = false) {
|
|
16
40
|
const result = { extractDir: '', tmpDir: '' };
|
|
@@ -55,7 +79,7 @@ async function extractZip(name, zip, hideLogs = false) {
|
|
|
55
79
|
logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.extractZip.success`));
|
|
56
80
|
return result;
|
|
57
81
|
}
|
|
58
|
-
async function copySourceToDest(src, dest, { sourceDir, includesRootDir = true, hideLogs = false, } = {}) {
|
|
82
|
+
async function copySourceToDest(src, dest, { sourceDir, includesRootDir = true, hideLogs = false, handleCollision, } = {}) {
|
|
59
83
|
try {
|
|
60
84
|
if (!hideLogs) {
|
|
61
85
|
logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.copySourceToDest.init`));
|
|
@@ -73,11 +97,43 @@ async function copySourceToDest(src, dest, { sourceDir, includesRootDir = true,
|
|
|
73
97
|
}
|
|
74
98
|
srcDirPath.push(rootDir);
|
|
75
99
|
}
|
|
100
|
+
const sourceDirs = [];
|
|
76
101
|
if (sourceDir) {
|
|
77
|
-
|
|
102
|
+
sourceDirs.push(...(Array.isArray(sourceDir) ? new Set(sourceDir) : [sourceDir]));
|
|
103
|
+
}
|
|
104
|
+
if (sourceDirs.length === 0) {
|
|
105
|
+
const projectSrcDir = (0, path_1.join)(...srcDirPath);
|
|
106
|
+
await fs_extra_1.default.copy(projectSrcDir, dest);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
for (let i = 0; i < sourceDirs.length; i++) {
|
|
110
|
+
const projectSrcDir = (0, path_1.join)(...srcDirPath, sourceDirs[i]);
|
|
111
|
+
let collisions = [];
|
|
112
|
+
let filesWithoutCollisions = [];
|
|
113
|
+
if (fs_extra_1.default.existsSync(dest) &&
|
|
114
|
+
handleCollision &&
|
|
115
|
+
typeof handleCollision === 'function') {
|
|
116
|
+
const existingFiles = (await (0, fs_1.walk)(dest, ['node_modules'])).map(file => path_1.default.normalize(path_1.default.relative(dest, file)));
|
|
117
|
+
const newFiles = (await (0, fs_1.walk)(projectSrcDir, ['node_modules'])).map(file => path_1.default.relative(projectSrcDir, file));
|
|
118
|
+
// Find files that exist in the same positions in both directories
|
|
119
|
+
collisions = existingFiles.filter(currentFile => newFiles.includes(currentFile));
|
|
120
|
+
filesWithoutCollisions = newFiles.filter(currentFile => !collisions.includes(currentFile));
|
|
121
|
+
}
|
|
122
|
+
if (collisions.length &&
|
|
123
|
+
handleCollision &&
|
|
124
|
+
typeof handleCollision === 'function') {
|
|
125
|
+
await handleCollision({
|
|
126
|
+
dest,
|
|
127
|
+
src: projectSrcDir,
|
|
128
|
+
collisions,
|
|
129
|
+
});
|
|
130
|
+
await Promise.all(filesWithoutCollisions.map(currentFile => fs_extra_1.default.copy(path_1.default.join(projectSrcDir, currentFile), path_1.default.join(dest, currentFile))));
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
await fs_extra_1.default.copy(projectSrcDir, dest);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
78
136
|
}
|
|
79
|
-
const projectSrcDir = (0, path_1.join)(...srcDirPath);
|
|
80
|
-
await fs_extra_1.default.copy(projectSrcDir, dest);
|
|
81
137
|
logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.copySourceToDest.success`));
|
|
82
138
|
return true;
|
|
83
139
|
}
|
|
@@ -99,7 +155,7 @@ async function cleanupTempDir(tmpDir) {
|
|
|
99
155
|
logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.cleanupTempDir.error`, { tmpDir }));
|
|
100
156
|
}
|
|
101
157
|
}
|
|
102
|
-
async function extractZipArchive(zip, name, dest, { sourceDir, includesRootDir, hideLogs } = {}) {
|
|
158
|
+
async function extractZipArchive(zip, name, dest, { sourceDir, includesRootDir, hideLogs, handleCollision, } = {}) {
|
|
103
159
|
let success = false;
|
|
104
160
|
if (zip) {
|
|
105
161
|
const { extractDir, tmpDir } = await extractZip(name, zip, hideLogs);
|
|
@@ -108,6 +164,7 @@ async function extractZipArchive(zip, name, dest, { sourceDir, includesRootDir,
|
|
|
108
164
|
sourceDir,
|
|
109
165
|
includesRootDir,
|
|
110
166
|
hideLogs,
|
|
167
|
+
handleCollision,
|
|
111
168
|
});
|
|
112
169
|
}
|
|
113
170
|
await cleanupTempDir(tmpDir);
|
package/lib/cms/uploadFolder.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
159
|
-
|
|
160
|
-
|
|
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
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/github.js
CHANGED
|
@@ -24,6 +24,7 @@ async function fetchFileFromRepository(repoPath, filePath, ref) {
|
|
|
24
24
|
return data;
|
|
25
25
|
}
|
|
26
26
|
catch (err) {
|
|
27
|
+
checkGithubRateLimit(err);
|
|
27
28
|
throw new Error((0, lang_1.i18n)(`${i18nKey}.fetchFileFromRepository.errors.fetchFail`), {
|
|
28
29
|
cause: err,
|
|
29
30
|
});
|
|
@@ -43,6 +44,7 @@ async function fetchReleaseData(repoPath, tag) {
|
|
|
43
44
|
return data;
|
|
44
45
|
}
|
|
45
46
|
catch (err) {
|
|
47
|
+
checkGithubRateLimit(err);
|
|
46
48
|
throw new Error((0, lang_1.i18n)(`${i18nKey}.fetchReleaseData.errors.fetchFail`, {
|
|
47
49
|
tag: tag || 'latest',
|
|
48
50
|
}), { cause: err });
|
|
@@ -72,13 +74,14 @@ async function downloadGithubRepoZip(repoPath, isRelease = false, options = {})
|
|
|
72
74
|
return data;
|
|
73
75
|
}
|
|
74
76
|
catch (err) {
|
|
77
|
+
checkGithubRateLimit(err);
|
|
75
78
|
throw new Error((0, lang_1.i18n)(`${i18nKey}.downloadGithubRepoZip.errors.fetchFail`), {
|
|
76
79
|
cause: err,
|
|
77
80
|
});
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
async function cloneGithubRepo(repoPath, dest, options = {}) {
|
|
81
|
-
const { tag, isRelease, branch, sourceDir, type, hideLogs } = options;
|
|
84
|
+
const { tag, isRelease, branch, sourceDir, type, hideLogs, handleCollision } = options;
|
|
82
85
|
const zip = await downloadGithubRepoZip(repoPath, isRelease, {
|
|
83
86
|
tag,
|
|
84
87
|
branch,
|
|
@@ -87,6 +90,7 @@ async function cloneGithubRepo(repoPath, dest, options = {}) {
|
|
|
87
90
|
const success = await (0, archive_1.extractZipArchive)(zip, repoName, dest, {
|
|
88
91
|
sourceDir,
|
|
89
92
|
hideLogs,
|
|
93
|
+
handleCollision,
|
|
90
94
|
});
|
|
91
95
|
if (success && !hideLogs) {
|
|
92
96
|
logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.cloneGithubRepo.success`, {
|
|
@@ -146,6 +150,7 @@ async function downloadGithubRepoContents(repoPath, contentPath, dest, ref, filt
|
|
|
146
150
|
await Promise.all(contentPromises);
|
|
147
151
|
}
|
|
148
152
|
catch (e) {
|
|
153
|
+
checkGithubRateLimit(e);
|
|
149
154
|
if ((0, errors_1.isSystemError)(e) && e?.error?.message) {
|
|
150
155
|
throw new Error((0, lang_1.i18n)(`${i18nKey}.downloadGithubRepoContents.errors.fetchFail`, {
|
|
151
156
|
errorMessage: e.error.message,
|
|
@@ -165,6 +170,7 @@ async function listGithubRepoContents(repoPath, contentPath, fileFilter) {
|
|
|
165
170
|
return filteredFiles;
|
|
166
171
|
}
|
|
167
172
|
catch (e) {
|
|
173
|
+
checkGithubRateLimit(e);
|
|
168
174
|
if ((0, errors_1.isHubSpotHttpError)(e) && e.data.message) {
|
|
169
175
|
throw new Error((0, lang_1.i18n)(`${i18nKey}.downloadGithubRepoContents.errors.fetchFail`, {
|
|
170
176
|
errorMessage: e.data.message,
|
|
@@ -174,3 +180,10 @@ async function listGithubRepoContents(repoPath, contentPath, fileFilter) {
|
|
|
174
180
|
}
|
|
175
181
|
}
|
|
176
182
|
exports.listGithubRepoContents = listGithubRepoContents;
|
|
183
|
+
function checkGithubRateLimit(err) {
|
|
184
|
+
if ((0, errors_1.isGithubRateLimitError)(err)) {
|
|
185
|
+
throw new Error((0, lang_1.i18n)(`${i18nKey}.rateLimitError`), {
|
|
186
|
+
cause: err,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hubspot/local-dev-lib",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2-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-beta.0",
|
|
23
24
|
"@inquirer/prompts": "^7.0.1",
|
|
24
25
|
"@types/content-disposition": "^0.5.5",
|
|
25
26
|
"@types/cors": "^2.8.15",
|
|
@@ -61,7 +62,7 @@
|
|
|
61
62
|
},
|
|
62
63
|
"dependencies": {
|
|
63
64
|
"address": "2.0.2",
|
|
64
|
-
"axios": "1.
|
|
65
|
+
"axios": "1.12.0",
|
|
65
66
|
"chalk": "2.4.2",
|
|
66
67
|
"chokidar": "3.6.0",
|
|
67
68
|
"content-disposition": "0.5.4",
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
"express": "4.21.2",
|
|
71
72
|
"extract-zip": "2.0.1",
|
|
72
73
|
"findup-sync": "5.0.0",
|
|
74
|
+
"form-data": "^4.0.4",
|
|
73
75
|
"fs-extra": "11.2.0",
|
|
74
76
|
"ignore": "5.3.1",
|
|
75
77
|
"js-yaml": "4.1.0",
|
package/types/Archive.d.ts
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
export interface Collision {
|
|
2
|
+
dest: string;
|
|
3
|
+
src: string;
|
|
4
|
+
collisions: string[];
|
|
5
|
+
}
|
|
1
6
|
export type ZipData = {
|
|
2
7
|
extractDir: string;
|
|
3
8
|
tmpDir: string;
|
|
4
9
|
};
|
|
5
10
|
export type CopySourceToDestOptions = {
|
|
6
|
-
sourceDir?: string;
|
|
11
|
+
sourceDir?: string | string[];
|
|
7
12
|
includesRootDir?: boolean;
|
|
8
13
|
hideLogs?: boolean;
|
|
14
|
+
handleCollision?: (collision: Collision) => void | Promise<void>;
|
|
9
15
|
};
|
package/types/Config.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface CLIConfig_NEW {
|
|
|
12
12
|
httpTimeout?: number;
|
|
13
13
|
env?: Environment;
|
|
14
14
|
httpUseLocalhost?: boolean;
|
|
15
|
+
autoOpenBrowser?: boolean;
|
|
16
|
+
flags?: Array<string>;
|
|
15
17
|
}
|
|
16
18
|
export interface CLIConfig_DEPRECATED {
|
|
17
19
|
portals: Array<CLIAccount_DEPRECATED>;
|
|
@@ -23,6 +25,8 @@ export interface CLIConfig_DEPRECATED {
|
|
|
23
25
|
httpTimeout?: number;
|
|
24
26
|
env?: Environment;
|
|
25
27
|
httpUseLocalhost?: boolean;
|
|
28
|
+
autoOpenBrowser?: boolean;
|
|
29
|
+
flags?: Array<string>;
|
|
26
30
|
}
|
|
27
31
|
export type CLIConfig = CLIConfig_NEW | CLIConfig_DEPRECATED;
|
|
28
32
|
export type Environment = ValueOf<typeof ENVIRONMENTS> | '';
|
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
package/types/Deploy.d.ts
CHANGED
|
@@ -35,9 +35,24 @@ export type DeployStatusTaskLocator = {
|
|
|
35
35
|
status: string;
|
|
36
36
|
}>;
|
|
37
37
|
};
|
|
38
|
-
export type
|
|
38
|
+
export type ProjectDeployResponseQueued = {
|
|
39
39
|
id: string;
|
|
40
|
+
buildResultType: 'DEPLOY_QUEUED';
|
|
40
41
|
links: {
|
|
41
42
|
status: string;
|
|
42
43
|
};
|
|
43
44
|
};
|
|
45
|
+
export type SubdeployValidationIssue = {
|
|
46
|
+
uid: string;
|
|
47
|
+
componentTypeName: string;
|
|
48
|
+
errorMessages: string[];
|
|
49
|
+
blockingMessages: {
|
|
50
|
+
message: string;
|
|
51
|
+
isWarning: boolean;
|
|
52
|
+
}[];
|
|
53
|
+
};
|
|
54
|
+
export type ProjectDeployResponseBlocked = {
|
|
55
|
+
buildResultType: 'DEPLOY_BLOCKED';
|
|
56
|
+
issues: SubdeployValidationIssue[];
|
|
57
|
+
};
|
|
58
|
+
export type ProjectDeployResponse = ProjectDeployResponseQueued | ProjectDeployResponseBlocked;
|
package/types/Github.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Collision } from './Archive';
|
|
1
2
|
type GithubAuthor = {
|
|
2
3
|
login: string;
|
|
3
4
|
id: number;
|
|
@@ -71,7 +72,8 @@ export type CloneGithubRepoOptions = {
|
|
|
71
72
|
type?: string;
|
|
72
73
|
branch?: string;
|
|
73
74
|
tag?: string;
|
|
74
|
-
sourceDir?: string;
|
|
75
|
+
sourceDir?: string | string[];
|
|
75
76
|
hideLogs?: boolean;
|
|
77
|
+
handleCollision?: (collision: Collision) => void;
|
|
76
78
|
};
|
|
77
79
|
export {};
|
package/types/Sandbox.d.ts
CHANGED
|
@@ -111,6 +111,33 @@ export type Sandbox = {
|
|
|
111
111
|
requestAccessFrom?: User | null;
|
|
112
112
|
superAdminsInSandbox?: number;
|
|
113
113
|
};
|
|
114
|
+
export declare const SandboxVersioning: {
|
|
115
|
+
readonly V1: "V1";
|
|
116
|
+
readonly V2: "V2";
|
|
117
|
+
};
|
|
118
|
+
export declare const SandboxStatus: {
|
|
119
|
+
readonly PENDING: "PENDING";
|
|
120
|
+
readonly READY: "READY";
|
|
121
|
+
readonly FAILED: "FAILED";
|
|
122
|
+
};
|
|
123
|
+
export type SandboxVersion = keyof typeof SandboxVersioning;
|
|
124
|
+
export type V2SandboxStatus = keyof typeof SandboxStatus;
|
|
125
|
+
export type V2Sandbox = {
|
|
126
|
+
sandboxHubId: number;
|
|
127
|
+
parentHubId: number;
|
|
128
|
+
name: string;
|
|
129
|
+
version: SandboxVersion;
|
|
130
|
+
type: string;
|
|
131
|
+
status: V2SandboxStatus;
|
|
132
|
+
createdAt: string;
|
|
133
|
+
createdByUser: User;
|
|
134
|
+
currentUserHasAccess?: boolean;
|
|
135
|
+
currentUserHasSuperAdminAccess?: boolean;
|
|
136
|
+
superAdminsInSandbox?: number;
|
|
137
|
+
requestAccessFrom?: User | null;
|
|
138
|
+
updatedAt?: string;
|
|
139
|
+
updatedByUser?: User | null;
|
|
140
|
+
};
|
|
114
141
|
export type SandboxResponse = {
|
|
115
142
|
sandbox: Sandbox;
|
|
116
143
|
personalAccessKey: string;
|
|
@@ -152,4 +179,10 @@ export type SandboxType = {
|
|
|
152
179
|
export type FetchTypesResponse = {
|
|
153
180
|
results: Array<SandboxType>;
|
|
154
181
|
};
|
|
182
|
+
export type SandboxPersonalAccessKey = {
|
|
183
|
+
personalAccessKey: {
|
|
184
|
+
encodedOAuthRefreshToken: string;
|
|
185
|
+
oauthAccessToken: string;
|
|
186
|
+
};
|
|
187
|
+
};
|
|
155
188
|
export {};
|
package/types/Sandbox.js
CHANGED
|
@@ -1,2 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SandboxStatus = exports.SandboxVersioning = void 0;
|
|
4
|
+
exports.SandboxVersioning = {
|
|
5
|
+
V1: 'V1',
|
|
6
|
+
V2: 'V2',
|
|
7
|
+
};
|
|
8
|
+
exports.SandboxStatus = {
|
|
9
|
+
PENDING: 'PENDING',
|
|
10
|
+
READY: 'READY',
|
|
11
|
+
FAILED: 'FAILED',
|
|
12
|
+
};
|