@hubspot/local-dev-lib 3.16.0 → 3.17.0-beta.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/crm.d.ts +3 -0
- package/api/crm.js +29 -0
- package/lang/en.json +8 -0
- package/lib/cms/uploadFolder.js +35 -13
- package/lib/crm.d.ts +6 -0
- package/lib/crm.js +47 -0
- package/lib/isDeepEqual.d.ts +1 -0
- package/lib/isDeepEqual.js +35 -0
- package/package.json +2 -1
- package/types/Crm.d.ts +26 -0
- package/types/Crm.js +2 -0
package/api/crm.d.ts
ADDED
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/lang/en.json
CHANGED
|
@@ -78,6 +78,14 @@
|
|
|
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
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
81
89
|
"cms": {
|
|
82
90
|
"modules": {
|
|
83
91
|
"createModule": {
|
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,47 @@
|
|
|
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
|
+
dataFileNames.forEach(fileName => {
|
|
16
|
+
if (!fileExists(fileName)) {
|
|
17
|
+
throw new Error((0, lang_1.i18n)('lib.crm.importData.errors.fileNotFound', { fileName }));
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
return { importRequest, dataFileNames };
|
|
21
|
+
}
|
|
22
|
+
exports.getImportDataRequest = getImportDataRequest;
|
|
23
|
+
function validateImportRequestFile(fileName) {
|
|
24
|
+
if (!fileExists(fileName)) {
|
|
25
|
+
throw new Error((0, lang_1.i18n)('lib.crm.importData.errors.fileNotFound', { fileName }));
|
|
26
|
+
}
|
|
27
|
+
if (path_1.default.extname(fileName) !== '.json') {
|
|
28
|
+
throw new Error((0, lang_1.i18n)('lib.crm.importData.errors.notJson'));
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
exports.validateImportRequestFile = validateImportRequestFile;
|
|
32
|
+
function fileExists(_path) {
|
|
33
|
+
try {
|
|
34
|
+
const absoluteSrcPath = path_1.default.resolve((0, path_2.getCwd)(), _path);
|
|
35
|
+
if (!absoluteSrcPath)
|
|
36
|
+
return false;
|
|
37
|
+
const stats = fs_extra_1.default.statSync(absoluteSrcPath);
|
|
38
|
+
const isFile = stats.isFile();
|
|
39
|
+
if (!isFile) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (e) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
@@ -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": "3.
|
|
3
|
+
"version": "3.17.0-beta.0",
|
|
4
4
|
"description": "Provides library functionality for HubSpot local development tooling, including the HubSpot CLI",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
"express": "4.21.2",
|
|
71
71
|
"extract-zip": "2.0.1",
|
|
72
72
|
"findup-sync": "5.0.0",
|
|
73
|
+
"form-data": "^4.0.4",
|
|
73
74
|
"fs-extra": "11.2.0",
|
|
74
75
|
"ignore": "5.3.1",
|
|
75
76
|
"js-yaml": "4.1.0",
|
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