@hubspot/local-dev-lib 0.0.1-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.
Files changed (230) hide show
  1. package/LICENSE +12 -0
  2. package/README.md +17 -0
  3. package/api/appsDev.d.ts +6 -0
  4. package/api/appsDev.js +29 -0
  5. package/api/customObjects.d.ts +8 -0
  6. package/api/customObjects.js +45 -0
  7. package/api/designManager.d.ts +5 -0
  8. package/api/designManager.js +18 -0
  9. package/api/developerTestAccounts.d.ts +7 -0
  10. package/api/developerTestAccounts.js +48 -0
  11. package/api/fileManager.d.ts +6 -0
  12. package/api/fileManager.js +63 -0
  13. package/api/fileMapper.d.ts +12 -0
  14. package/api/fileMapper.js +106 -0
  15. package/api/fileTransport.d.ts +4 -0
  16. package/api/fileTransport.js +39 -0
  17. package/api/functions.d.ts +8 -0
  18. package/api/functions.js +43 -0
  19. package/api/github.d.ts +11 -0
  20. package/api/github.js +71 -0
  21. package/api/hubdb.d.ts +12 -0
  22. package/api/hubdb.js +67 -0
  23. package/api/lighthouseScore.d.ts +6 -0
  24. package/api/lighthouseScore.js +26 -0
  25. package/api/localDevAuth.d.ts +8 -0
  26. package/api/localDevAuth.js +53 -0
  27. package/api/marketplaceValidation.d.ts +6 -0
  28. package/api/marketplaceValidation.js +26 -0
  29. package/api/projects.d.ts +40 -0
  30. package/api/projects.js +216 -0
  31. package/api/sandboxHubs.d.ts +7 -0
  32. package/api/sandboxHubs.js +49 -0
  33. package/api/sandboxSync.d.ts +4 -0
  34. package/api/sandboxSync.js +26 -0
  35. package/api/secrets.d.ts +6 -0
  36. package/api/secrets.js +37 -0
  37. package/api/validateHubl.d.ts +3 -0
  38. package/api/validateHubl.js +15 -0
  39. package/config/CLIConfiguration.d.ts +62 -0
  40. package/config/CLIConfiguration.js +467 -0
  41. package/config/configFile.d.ts +21 -0
  42. package/config/configFile.js +102 -0
  43. package/config/configUtils.d.ts +5 -0
  44. package/config/configUtils.js +87 -0
  45. package/config/config_DEPRECATED.d.ts +75 -0
  46. package/config/config_DEPRECATED.js +678 -0
  47. package/config/environment.d.ts +2 -0
  48. package/config/environment.js +60 -0
  49. package/config/getAccountIdentifier.d.ts +2 -0
  50. package/config/getAccountIdentifier.js +15 -0
  51. package/config/index.d.ts +41 -0
  52. package/config/index.js +260 -0
  53. package/constants/api.d.ts +15 -0
  54. package/constants/api.js +18 -0
  55. package/constants/auth.d.ts +37 -0
  56. package/constants/auth.js +38 -0
  57. package/constants/config.d.ts +18 -0
  58. package/constants/config.js +22 -0
  59. package/constants/environments.d.ts +15 -0
  60. package/constants/environments.js +18 -0
  61. package/constants/extensions.d.ts +6 -0
  62. package/constants/extensions.js +28 -0
  63. package/constants/files.d.ts +21 -0
  64. package/constants/files.js +24 -0
  65. package/constants/ports.d.ts +3 -0
  66. package/constants/ports.js +6 -0
  67. package/enums/build.d.ts +36 -0
  68. package/enums/build.js +39 -0
  69. package/enums/deploy.d.ts +11 -0
  70. package/enums/deploy.js +14 -0
  71. package/enums/project.d.ts +6 -0
  72. package/enums/project.js +9 -0
  73. package/errors/errors_DEPRECATED.d.ts +3 -0
  74. package/errors/errors_DEPRECATED.js +60 -0
  75. package/errors/index.d.ts +18 -0
  76. package/errors/index.js +63 -0
  77. package/http/addQueryParams.d.ts +2 -0
  78. package/http/addQueryParams.js +14 -0
  79. package/http/getAxiosConfig.d.ts +9 -0
  80. package/http/getAxiosConfig.js +66 -0
  81. package/http/index.d.ts +17 -0
  82. package/http/index.js +173 -0
  83. package/http/unauthed.d.ts +15 -0
  84. package/http/unauthed.js +38 -0
  85. package/lang/en.json +389 -0
  86. package/lib/archive.d.ts +3 -0
  87. package/lib/archive.js +117 -0
  88. package/lib/cms/functions.d.ts +8 -0
  89. package/lib/cms/functions.js +181 -0
  90. package/lib/cms/handleFieldsJS.d.ts +33 -0
  91. package/lib/cms/handleFieldsJS.js +148 -0
  92. package/lib/cms/modules.d.ts +14 -0
  93. package/lib/cms/modules.js +186 -0
  94. package/lib/cms/processFieldsJs.d.ts +1 -0
  95. package/lib/cms/processFieldsJs.js +97 -0
  96. package/lib/cms/templates.d.ts +65 -0
  97. package/lib/cms/templates.js +107 -0
  98. package/lib/cms/themes.d.ts +2 -0
  99. package/lib/cms/themes.js +34 -0
  100. package/lib/cms/uploadFolder.d.ts +7 -0
  101. package/lib/cms/uploadFolder.js +202 -0
  102. package/lib/cms/validate.d.ts +2 -0
  103. package/lib/cms/validate.js +40 -0
  104. package/lib/cms/watch.d.ts +4 -0
  105. package/lib/cms/watch.js +201 -0
  106. package/lib/customObjects.d.ts +5 -0
  107. package/lib/customObjects.js +42 -0
  108. package/lib/environment.d.ts +2 -0
  109. package/lib/environment.js +16 -0
  110. package/lib/escapeRegExp.d.ts +1 -0
  111. package/lib/escapeRegExp.js +7 -0
  112. package/lib/fileManager.d.ts +2 -0
  113. package/lib/fileManager.js +184 -0
  114. package/lib/fileMapper.d.ts +18 -0
  115. package/lib/fileMapper.js +317 -0
  116. package/lib/fs.d.ts +4 -0
  117. package/lib/fs.js +71 -0
  118. package/lib/github.d.ts +8 -0
  119. package/lib/github.js +167 -0
  120. package/lib/gitignore.d.ts +3 -0
  121. package/lib/gitignore.js +49 -0
  122. package/lib/hubdb.d.ts +17 -0
  123. package/lib/hubdb.js +133 -0
  124. package/lib/ignoreRules.d.ts +3 -0
  125. package/lib/ignoreRules.js +69 -0
  126. package/lib/logger.d.ts +56 -0
  127. package/lib/logger.js +146 -0
  128. package/lib/notify.d.ts +1 -0
  129. package/lib/notify.js +43 -0
  130. package/lib/oauth.d.ts +4 -0
  131. package/lib/oauth.js +34 -0
  132. package/lib/path.d.ts +14 -0
  133. package/lib/path.js +134 -0
  134. package/lib/personalAccessKey.d.ts +10 -0
  135. package/lib/personalAccessKey.js +163 -0
  136. package/lib/portManager.d.ts +10 -0
  137. package/lib/portManager.js +46 -0
  138. package/lib/text.d.ts +2 -0
  139. package/lib/text.js +24 -0
  140. package/lib/trackUsage.d.ts +1 -0
  141. package/lib/trackUsage.js +63 -0
  142. package/lib/urls.d.ts +2 -0
  143. package/lib/urls.js +24 -0
  144. package/models/FileSystemError.d.ts +6 -0
  145. package/models/FileSystemError.js +47 -0
  146. package/models/HubSpotHttpError.d.ts +24 -0
  147. package/models/HubSpotHttpError.js +197 -0
  148. package/models/OAuth2Manager.d.ts +12 -0
  149. package/models/OAuth2Manager.js +105 -0
  150. package/package.json +81 -0
  151. package/types/Accounts.d.ts +178 -0
  152. package/types/Accounts.js +2 -0
  153. package/types/Activity.d.ts +20 -0
  154. package/types/Activity.js +2 -0
  155. package/types/Api.d.ts +2 -0
  156. package/types/Api.js +2 -0
  157. package/types/Apps.d.ts +77 -0
  158. package/types/Apps.js +2 -0
  159. package/types/Archive.d.ts +9 -0
  160. package/types/Archive.js +2 -0
  161. package/types/Build.d.ts +41 -0
  162. package/types/Build.js +2 -0
  163. package/types/CLIOptions.d.ts +8 -0
  164. package/types/CLIOptions.js +2 -0
  165. package/types/ComponentStructure.d.ts +40 -0
  166. package/types/ComponentStructure.js +2 -0
  167. package/types/Config.d.ts +37 -0
  168. package/types/Config.js +2 -0
  169. package/types/Deploy.d.ts +42 -0
  170. package/types/Deploy.js +2 -0
  171. package/types/DesignManager.d.ts +10 -0
  172. package/types/DesignManager.js +2 -0
  173. package/types/Error.d.ts +37 -0
  174. package/types/Error.js +2 -0
  175. package/types/FieldsJS.d.ts +1 -0
  176. package/types/FieldsJS.js +2 -0
  177. package/types/FileManager.d.ts +71 -0
  178. package/types/FileManager.js +2 -0
  179. package/types/Files.d.ts +79 -0
  180. package/types/Files.js +2 -0
  181. package/types/Functions.d.ts +66 -0
  182. package/types/Functions.js +2 -0
  183. package/types/Github.d.ts +76 -0
  184. package/types/Github.js +2 -0
  185. package/types/Http.d.ts +29 -0
  186. package/types/Http.js +2 -0
  187. package/types/Hubdb.d.ts +109 -0
  188. package/types/Hubdb.js +2 -0
  189. package/types/HublValidation.d.ts +59 -0
  190. package/types/HublValidation.js +2 -0
  191. package/types/Lang.d.ts +10 -0
  192. package/types/Lang.js +2 -0
  193. package/types/Lighthouse.d.ts +25 -0
  194. package/types/Lighthouse.js +2 -0
  195. package/types/MarketplaceValidation.d.ts +28 -0
  196. package/types/MarketplaceValidation.js +2 -0
  197. package/types/Migration.d.ts +28 -0
  198. package/types/Migration.js +10 -0
  199. package/types/Modules.d.ts +16 -0
  200. package/types/Modules.js +2 -0
  201. package/types/PortManager.d.ts +11 -0
  202. package/types/PortManager.js +2 -0
  203. package/types/Project.d.ts +42 -0
  204. package/types/Project.js +2 -0
  205. package/types/ProjectLog.d.ts +9 -0
  206. package/types/ProjectLog.js +2 -0
  207. package/types/Sandbox.d.ts +155 -0
  208. package/types/Sandbox.js +2 -0
  209. package/types/Schemas.d.ts +39 -0
  210. package/types/Schemas.js +2 -0
  211. package/types/Secrets.d.ts +3 -0
  212. package/types/Secrets.js +2 -0
  213. package/types/Utils.d.ts +6 -0
  214. package/types/Utils.js +2 -0
  215. package/types/developerTestAccounts.d.ts +12 -0
  216. package/types/developerTestAccounts.js +2 -0
  217. package/utils/PortManagerServer.d.ts +26 -0
  218. package/utils/PortManagerServer.js +158 -0
  219. package/utils/accounts.d.ts +4 -0
  220. package/utils/accounts.js +28 -0
  221. package/utils/cms/fieldsJS.d.ts +2 -0
  222. package/utils/cms/fieldsJS.js +18 -0
  223. package/utils/cms/modules.d.ts +4 -0
  224. package/utils/cms/modules.js +54 -0
  225. package/utils/detectPort.d.ts +1 -0
  226. package/utils/detectPort.js +102 -0
  227. package/utils/git.d.ts +3 -0
  228. package/utils/git.js +71 -0
  229. package/utils/lang.d.ts +6 -0
  230. package/utils/lang.js +88 -0
@@ -0,0 +1,5 @@
1
+ import { Schema } from '../types/Schemas';
2
+ export declare function getResolvedPath(dest?: string, name?: string): string;
3
+ export declare function writeSchemaToDisk(schema: Schema, dest?: string): Promise<void>;
4
+ export declare function downloadSchemas(accountId: number, dest?: string): Promise<Array<Schema>>;
5
+ export declare function downloadSchema(accountId: number, schemaObjectType: string, dest?: string): Promise<Schema>;
@@ -0,0 +1,42 @@
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.downloadSchema = exports.downloadSchemas = exports.writeSchemaToDisk = exports.getResolvedPath = void 0;
7
+ const fs_extra_1 = __importDefault(require("fs-extra"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const prettier_1 = __importDefault(require("prettier"));
10
+ const path_2 = require("../lib/path");
11
+ const customObjects_1 = require("../api/customObjects");
12
+ function getResolvedPath(dest, name) {
13
+ if (name)
14
+ return path_1.default.resolve((0, path_2.getCwd)(), dest || '', `${name}.json`);
15
+ return path_1.default.resolve((0, path_2.getCwd)(), dest || '');
16
+ }
17
+ exports.getResolvedPath = getResolvedPath;
18
+ async function writeSchemaToDisk(schema, dest) {
19
+ const formattedSchema = await prettier_1.default.format(JSON.stringify(schema), {
20
+ parser: 'json',
21
+ });
22
+ fs_extra_1.default.outputFileSync(getResolvedPath(dest, schema.name), formattedSchema);
23
+ }
24
+ exports.writeSchemaToDisk = writeSchemaToDisk;
25
+ async function downloadSchemas(accountId, dest) {
26
+ const axiosResponse = await (0, customObjects_1.fetchObjectSchemas)(accountId);
27
+ const response = axiosResponse.data;
28
+ if (response.results.length) {
29
+ for (const schema of response.results) {
30
+ await writeSchemaToDisk(schema, dest);
31
+ }
32
+ }
33
+ return response.results;
34
+ }
35
+ exports.downloadSchemas = downloadSchemas;
36
+ async function downloadSchema(accountId, schemaObjectType, dest) {
37
+ const axiosResponse = await (0, customObjects_1.fetchObjectSchema)(accountId, schemaObjectType);
38
+ const response = axiosResponse.data;
39
+ await writeSchemaToDisk(response, dest);
40
+ return response;
41
+ }
42
+ exports.downloadSchema = downloadSchema;
@@ -0,0 +1,2 @@
1
+ import { Environment } from '../types/Config';
2
+ export declare function getValidEnv(env?: Environment | null, maskedProductionValue?: Environment): Environment;
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getValidEnv = void 0;
4
+ const environments_1 = require("../constants/environments");
5
+ function getValidEnv(env, maskedProductionValue) {
6
+ const prodValue = typeof maskedProductionValue === 'string'
7
+ ? maskedProductionValue
8
+ : environments_1.ENVIRONMENTS.PROD;
9
+ const returnVal = typeof env &&
10
+ typeof env === 'string' &&
11
+ env.toLowerCase() === environments_1.ENVIRONMENTS.QA
12
+ ? environments_1.ENVIRONMENTS.QA
13
+ : prodValue;
14
+ return returnVal;
15
+ }
16
+ exports.getValidEnv = getValidEnv;
@@ -0,0 +1 @@
1
+ export declare function escapeRegExp(string: string): string;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.escapeRegExp = void 0;
4
+ function escapeRegExp(string) {
5
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
6
+ }
7
+ exports.escapeRegExp = escapeRegExp;
@@ -0,0 +1,2 @@
1
+ export declare function uploadFolder(accountId: number, src: string, dest: string): Promise<void>;
2
+ export declare function downloadFileOrFolder(accountId: number, src: string, dest: string, overwrite?: boolean, includeArchived?: boolean): Promise<void>;
@@ -0,0 +1,184 @@
1
+ "use strict";
2
+ // FILE MANAGER - not to be confused with fileMapper.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.downloadFileOrFolder = exports.uploadFolder = void 0;
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const fileManager_1 = require("../api/fileManager");
11
+ const fs_1 = require("./fs");
12
+ const logger_1 = require("./logger");
13
+ const ignoreRules_1 = require("./ignoreRules");
14
+ const http_1 = require("../http");
15
+ const escapeRegExp_1 = require("./escapeRegExp");
16
+ const path_2 = require("./path");
17
+ const lang_1 = require("../utils/lang");
18
+ const errors_1 = require("../errors");
19
+ const FileSystemError_1 = require("../models/FileSystemError");
20
+ const i18nKey = 'lib.fileManager';
21
+ async function uploadFolder(accountId, src, dest) {
22
+ const regex = new RegExp(`^${(0, escapeRegExp_1.escapeRegExp)(src)}`);
23
+ const files = await (0, fs_1.walk)(src);
24
+ const filesToUpload = files.filter((0, ignoreRules_1.createIgnoreFilter)(false));
25
+ const len = filesToUpload.length;
26
+ for (let index = 0; index < len; index++) {
27
+ const file = filesToUpload[index];
28
+ const relativePath = file.replace(regex, '');
29
+ const destPath = (0, path_2.convertToUnixPath)(path_1.default.join(dest, relativePath));
30
+ logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.uploadStarted`, {
31
+ file,
32
+ destPath,
33
+ accountId,
34
+ }));
35
+ try {
36
+ await (0, fileManager_1.uploadFile)(accountId, file, destPath);
37
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.uploadSuccess`, { file, destPath }));
38
+ }
39
+ catch (err) {
40
+ if ((0, errors_1.isHubSpotHttpError)(err)) {
41
+ err.updateContext({
42
+ filepath: file,
43
+ dest: destPath,
44
+ });
45
+ throw err;
46
+ }
47
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.uploadFailed`, {
48
+ file,
49
+ destPath,
50
+ }));
51
+ }
52
+ }
53
+ }
54
+ exports.uploadFolder = uploadFolder;
55
+ async function skipExisting(overwrite, filepath) {
56
+ if (overwrite) {
57
+ return false;
58
+ }
59
+ if (await fs_extra_1.default.pathExists(filepath)) {
60
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.skippedExisting`, { filepath }));
61
+ return true;
62
+ }
63
+ return false;
64
+ }
65
+ async function downloadFile(accountId, file, dest, overwrite) {
66
+ const fileName = `${file.name}.${file.extension}`;
67
+ const destPath = (0, path_2.convertToLocalFileSystemPath)(path_1.default.join(dest, fileName));
68
+ if (await skipExisting(overwrite || false, destPath)) {
69
+ return;
70
+ }
71
+ await http_1.http.getOctetStream(accountId, {
72
+ baseURL: file.url,
73
+ url: '',
74
+ }, destPath);
75
+ }
76
+ async function fetchAllPagedFiles(accountId, folderId, includeArchived) {
77
+ let totalFiles = null;
78
+ let files = [];
79
+ let count = 0;
80
+ let offset = 0;
81
+ while (totalFiles === null || count < totalFiles) {
82
+ const { data: response } = await (0, fileManager_1.fetchFiles)(accountId, folderId, offset, includeArchived);
83
+ if (totalFiles === null) {
84
+ totalFiles = response.total_count;
85
+ }
86
+ count += response.objects.length;
87
+ offset += response.objects.length;
88
+ files = files.concat(response.objects);
89
+ }
90
+ return files;
91
+ }
92
+ async function fetchFolderContents(accountId, folder, dest, overwrite, includeArchived) {
93
+ try {
94
+ await fs_extra_1.default.ensureDir(dest);
95
+ }
96
+ catch (err) {
97
+ throw new FileSystemError_1.FileSystemError({ cause: err }, {
98
+ dest,
99
+ accountId,
100
+ operation: 'write',
101
+ });
102
+ }
103
+ const files = await fetchAllPagedFiles(accountId, folder.id, includeArchived);
104
+ logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.fetchingFiles`, {
105
+ fileCount: files.length,
106
+ folderName: folder.name || '',
107
+ }));
108
+ for (const file of files) {
109
+ await downloadFile(accountId, file, dest, overwrite);
110
+ }
111
+ const { data: { objects: folders }, } = await (0, fileManager_1.fetchFolders)(accountId, folder.id);
112
+ for (const folder of folders) {
113
+ const nestedFolder = path_1.default.join(dest, folder.name);
114
+ await fetchFolderContents(accountId, folder, nestedFolder, overwrite, includeArchived);
115
+ }
116
+ }
117
+ // Download a folder and write to local file system.
118
+ async function downloadFolder(accountId, src, dest, folder, overwrite, includeArchived) {
119
+ let absolutePath;
120
+ if (folder.name) {
121
+ absolutePath = (0, path_2.convertToLocalFileSystemPath)(path_1.default.resolve((0, path_2.getCwd)(), dest, folder.name));
122
+ }
123
+ else {
124
+ absolutePath = (0, path_2.convertToLocalFileSystemPath)(path_1.default.resolve((0, path_2.getCwd)(), dest));
125
+ }
126
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.fetchFolderStarted`, {
127
+ src,
128
+ path: absolutePath,
129
+ accountId,
130
+ }));
131
+ await fetchFolderContents(accountId, folder, absolutePath, overwrite, includeArchived);
132
+ logger_1.logger.success((0, lang_1.i18n)(`${i18nKey}.fetchFolderSuccess`, {
133
+ src,
134
+ dest,
135
+ }));
136
+ }
137
+ // Download a single file and write to local file system.
138
+ async function downloadSingleFile(accountId, src, dest, file, overwrite, includeArchived) {
139
+ if (!includeArchived && file.archived) {
140
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.archivedFile`, { src }));
141
+ }
142
+ if (file.hidden) {
143
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.hiddenFile`, { src }));
144
+ }
145
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.fetchFileStarted`, {
146
+ src,
147
+ dest,
148
+ accountId,
149
+ }));
150
+ await downloadFile(accountId, file, dest, overwrite);
151
+ logger_1.logger.success((0, lang_1.i18n)(`${i18nKey}.fetchFileSuccess`, {
152
+ src,
153
+ dest,
154
+ }));
155
+ }
156
+ // Lookup path in file manager and initiate download
157
+ async function downloadFileOrFolder(accountId, src, dest, overwrite, includeArchived) {
158
+ try {
159
+ if (src == '/') {
160
+ // Filemanager API treats 'None' as the root
161
+ const rootFolder = { id: 'None', name: '' };
162
+ await downloadFolder(accountId, src, dest, rootFolder, overwrite, includeArchived);
163
+ }
164
+ else {
165
+ const { data: { file, folder }, } = await (0, fileManager_1.fetchStat)(accountId, src);
166
+ if (file) {
167
+ await downloadSingleFile(accountId, src, dest, file, overwrite, includeArchived);
168
+ }
169
+ else if (folder) {
170
+ await downloadFolder(accountId, src, dest, folder, overwrite, includeArchived);
171
+ }
172
+ }
173
+ }
174
+ catch (err) {
175
+ if ((0, errors_1.isAuthError)(err)) {
176
+ err.updateContext({
177
+ request: src,
178
+ accountId,
179
+ });
180
+ }
181
+ throw err;
182
+ }
183
+ }
184
+ exports.downloadFileOrFolder = downloadFileOrFolder;
@@ -0,0 +1,18 @@
1
+ import { FileMapperNode, Mode, FileMapperOptions, FileMapperInputOptions, PathTypeData, RecursiveFileMapperCallback } from '../types/Files';
2
+ export declare function isPathToFile(filepath: string): boolean;
3
+ export declare function isPathToModule(filepath: string): boolean;
4
+ export declare function isPathToRoot(filepath: string): boolean;
5
+ export declare function isPathToHubspot(filepath: string): boolean;
6
+ export declare function getFileMapperQueryValues(mode?: Mode | null, { staging, assetVersion }?: FileMapperInputOptions): FileMapperOptions;
7
+ export declare function getTypeDataFromPath(src: string): PathTypeData;
8
+ export declare function recurseFolder(node: FileMapperNode, callback: RecursiveFileMapperCallback, filepath?: string, depth?: number): boolean;
9
+ export declare function writeUtimes(accountId: number, filepath: string, node: FileMapperNode): Promise<void>;
10
+ export declare function fetchFolderFromApi(accountId: number, src: string, mode?: Mode, options?: FileMapperInputOptions): Promise<FileMapperNode>;
11
+ /**
12
+ * Fetch a file/folder and write to local file system.
13
+ *
14
+ * @async
15
+ * @param {FileMapperInputArguments} input
16
+ * @returns {Promise}
17
+ */
18
+ export declare function downloadFileOrFolder(accountId: number, src: string, dest: string, mode?: Mode, options?: FileMapperInputOptions): Promise<void>;
@@ -0,0 +1,317 @@
1
+ "use strict";
2
+ // FILE MAPPER - not to be confused with fileManager.ts
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.downloadFileOrFolder = exports.fetchFolderFromApi = exports.writeUtimes = exports.recurseFolder = exports.getTypeDataFromPath = exports.getFileMapperQueryValues = exports.isPathToHubspot = exports.isPathToRoot = exports.isPathToModule = exports.isPathToFile = void 0;
8
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const p_queue_1 = __importDefault(require("p-queue"));
11
+ const path_2 = require("./path");
12
+ const logger_1 = require("./logger");
13
+ const fileMapper_1 = require("../api/fileMapper");
14
+ const extensions_1 = require("../constants/extensions");
15
+ const files_1 = require("../constants/files");
16
+ const errors_1 = require("../errors");
17
+ const lang_1 = require("../utils/lang");
18
+ const FileSystemError_1 = require("../models/FileSystemError");
19
+ const i18nKey = 'lib.fileMapper';
20
+ const queue = new p_queue_1.default({
21
+ concurrency: 10,
22
+ });
23
+ function isPathToFile(filepath) {
24
+ const ext = (0, path_2.getExt)(filepath);
25
+ return !!ext && ext !== extensions_1.MODULE_EXTENSION && ext !== extensions_1.FUNCTIONS_EXTENSION;
26
+ }
27
+ exports.isPathToFile = isPathToFile;
28
+ function isPathToModule(filepath) {
29
+ const ext = (0, path_2.getExt)(filepath);
30
+ return ext === extensions_1.MODULE_EXTENSION;
31
+ }
32
+ exports.isPathToModule = isPathToModule;
33
+ function isPathToRoot(filepath) {
34
+ if (typeof filepath !== 'string')
35
+ return false;
36
+ // Root pattern matches empty strings and: / \
37
+ return /^(\/|\\)?$/.test(filepath.trim());
38
+ }
39
+ exports.isPathToRoot = isPathToRoot;
40
+ function isPathToHubspot(filepath) {
41
+ if (typeof filepath !== 'string')
42
+ return false;
43
+ return /^(\/|\\)?@hubspot/i.test(filepath.trim());
44
+ }
45
+ exports.isPathToHubspot = isPathToHubspot;
46
+ function useApiBuffer(mode) {
47
+ return mode === files_1.MODE.draft;
48
+ }
49
+ // Determines API param based on mode an options
50
+ function getFileMapperQueryValues(mode, { staging, assetVersion } = {}) {
51
+ return {
52
+ params: {
53
+ buffer: useApiBuffer(mode),
54
+ environmentId: staging ? 2 : 1,
55
+ version: assetVersion,
56
+ },
57
+ };
58
+ }
59
+ exports.getFileMapperQueryValues = getFileMapperQueryValues;
60
+ // Determines version number to log based on input.options
61
+ function getAssetVersionIdentifier(assetVersion, src) {
62
+ if (typeof assetVersion !== 'undefined' &&
63
+ typeof src !== 'undefined' &&
64
+ src.startsWith('@hubspot/')) {
65
+ return ` v${assetVersion}`;
66
+ }
67
+ return '';
68
+ }
69
+ function validateFileMapperNode(node) {
70
+ if (node === Object(node))
71
+ return;
72
+ let json;
73
+ try {
74
+ json = JSON.stringify(node, null, 2);
75
+ }
76
+ catch (err) {
77
+ json = node;
78
+ }
79
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.invalidNode`, {
80
+ json: JSON.stringify(json),
81
+ }));
82
+ }
83
+ function getTypeDataFromPath(src) {
84
+ const isModule = isPathToModule(src);
85
+ const isHubspot = isPathToHubspot(src);
86
+ const isFile = !isModule && isPathToFile(src);
87
+ const isRoot = !isModule && !isFile && isPathToRoot(src);
88
+ const isFolder = !isFile;
89
+ return {
90
+ isModule,
91
+ isHubspot,
92
+ isFile,
93
+ isRoot,
94
+ isFolder,
95
+ };
96
+ }
97
+ exports.getTypeDataFromPath = getTypeDataFromPath;
98
+ function recurseFolder(node, callback, filepath = '', depth = 0) {
99
+ validateFileMapperNode(node);
100
+ const isRootFolder = node.folder && depth === 0;
101
+ if (isRootFolder) {
102
+ if (!filepath) {
103
+ filepath = node.name;
104
+ }
105
+ }
106
+ else {
107
+ filepath = path_1.default.join(filepath, node.name);
108
+ }
109
+ let __break = callback(node, filepath, depth);
110
+ if (__break === false)
111
+ return __break;
112
+ __break = node.children.every(childNode => {
113
+ __break = recurseFolder(childNode, callback, filepath, depth + 1);
114
+ return __break !== false;
115
+ });
116
+ return depth === 0 ? false : __break;
117
+ }
118
+ exports.recurseFolder = recurseFolder;
119
+ async function writeUtimes(accountId, filepath, node) {
120
+ try {
121
+ const now = new Date();
122
+ const atime = node.createdAt ? new Date(node.createdAt) : now;
123
+ const mtime = node.updatedAt ? new Date(node.updatedAt) : now;
124
+ await fs_extra_1.default.utimes(filepath, atime, mtime);
125
+ }
126
+ catch (err) {
127
+ throw new FileSystemError_1.FileSystemError({ cause: err }, {
128
+ filepath,
129
+ accountId,
130
+ operation: 'write',
131
+ });
132
+ }
133
+ }
134
+ exports.writeUtimes = writeUtimes;
135
+ async function skipExisting(filepath, overwrite = false) {
136
+ if (overwrite) {
137
+ return false;
138
+ }
139
+ if (await fs_extra_1.default.pathExists(filepath)) {
140
+ return true;
141
+ }
142
+ return false;
143
+ }
144
+ async function fetchAndWriteFileStream(accountId, srcPath, filepath, mode, options = {}) {
145
+ if (typeof srcPath !== 'string' || !srcPath.trim()) {
146
+ return;
147
+ }
148
+ if (await skipExisting(filepath, options.overwrite)) {
149
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.skippedExisting`, { filepath }));
150
+ return;
151
+ }
152
+ if (!(0, path_2.isAllowedExtension)(srcPath, Array.from(extensions_1.JSR_ALLOWED_EXTENSIONS))) {
153
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.invalidFileType`, { srcPath }));
154
+ }
155
+ const node = await (0, fileMapper_1.fetchFileStream)(accountId, srcPath, filepath, getFileMapperQueryValues(mode, options));
156
+ await writeUtimes(accountId, filepath, node);
157
+ }
158
+ // Writes an individual file or folder (not recursive). If file source is missing, the
159
+ //file is fetched.
160
+ async function writeFileMapperNode(accountId, filepath, node, mode, options = {}) {
161
+ const localFilepath = (0, path_2.convertToLocalFileSystemPath)(path_1.default.resolve(filepath));
162
+ if (await skipExisting(localFilepath, options.overwrite)) {
163
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.skippedExisting`, {
164
+ filepath: localFilepath,
165
+ }));
166
+ return true;
167
+ }
168
+ if (!node.folder) {
169
+ try {
170
+ await fetchAndWriteFileStream(accountId, node.path, localFilepath, mode, options);
171
+ return true;
172
+ }
173
+ catch (err) {
174
+ return false;
175
+ }
176
+ }
177
+ try {
178
+ await fs_extra_1.default.ensureDir(localFilepath);
179
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.wroteFolder`, {
180
+ filepath: localFilepath,
181
+ }));
182
+ }
183
+ catch (err) {
184
+ throw new FileSystemError_1.FileSystemError({ cause: err }, {
185
+ filepath: localFilepath,
186
+ accountId,
187
+ operation: 'write',
188
+ });
189
+ }
190
+ return true;
191
+ }
192
+ async function downloadFile(accountId, src, destPath, mode, options = {}) {
193
+ const { isFile, isHubspot } = getTypeDataFromPath(src);
194
+ if (!isFile) {
195
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.invalidRequest`, { src }));
196
+ }
197
+ try {
198
+ const dest = path_1.default.resolve(destPath);
199
+ const cwd = (0, path_2.getCwd)();
200
+ let filepath;
201
+ if (dest === cwd) {
202
+ // Dest: CWD
203
+ filepath = path_1.default.resolve(cwd, path_1.default.basename(src));
204
+ }
205
+ else if (isPathToFile(dest)) {
206
+ // Dest: file path
207
+ filepath = path_1.default.isAbsolute(dest) ? dest : path_1.default.resolve(cwd, dest);
208
+ }
209
+ else {
210
+ // Dest: folder path
211
+ const name = path_1.default.basename(src);
212
+ filepath = path_1.default.isAbsolute(dest)
213
+ ? path_1.default.resolve(dest, name)
214
+ : path_1.default.resolve(cwd, dest, name);
215
+ }
216
+ const localFsPath = (0, path_2.convertToLocalFileSystemPath)(filepath);
217
+ await fetchAndWriteFileStream(accountId, src, localFsPath, mode, options);
218
+ await queue.onIdle();
219
+ logger_1.logger.success((0, lang_1.i18n)(`${i18nKey}.completedFetch`, {
220
+ src,
221
+ version: getAssetVersionIdentifier(options.assetVersion, src),
222
+ dest,
223
+ }));
224
+ }
225
+ catch (err) {
226
+ const error = err;
227
+ if (isHubspot && (0, errors_1.isTimeoutError)(error)) {
228
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.assetTimeout`), { cause: error });
229
+ }
230
+ else {
231
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.failedToFetchFile`, { src, dest: destPath }), { cause: error });
232
+ }
233
+ }
234
+ }
235
+ async function fetchFolderFromApi(accountId, src, mode, options = {}) {
236
+ const { isRoot, isFolder, isHubspot } = getTypeDataFromPath(src);
237
+ if (!isFolder) {
238
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.invalidFetchFolderRequest`, {
239
+ src,
240
+ }));
241
+ }
242
+ const srcPath = isRoot ? '@root' : src;
243
+ const queryValues = getFileMapperQueryValues(mode, options);
244
+ const { data: node } = isHubspot
245
+ ? await (0, fileMapper_1.downloadDefault)(accountId, srcPath, queryValues)
246
+ : await (0, fileMapper_1.download)(accountId, srcPath, queryValues);
247
+ logger_1.logger.log((0, lang_1.i18n)(`${i18nKey}.folderFetch`, { src, accountId }));
248
+ return node;
249
+ }
250
+ exports.fetchFolderFromApi = fetchFolderFromApi;
251
+ async function downloadFolder(accountId, src, destPath, mode, options = {}) {
252
+ try {
253
+ const node = await fetchFolderFromApi(accountId, src, mode, options);
254
+ if (!node) {
255
+ return;
256
+ }
257
+ const dest = path_1.default.resolve(destPath);
258
+ const rootPath = dest === (0, path_2.getCwd)()
259
+ ? (0, path_2.convertToLocalFileSystemPath)(path_1.default.resolve(dest, node.name))
260
+ : dest;
261
+ let success = true;
262
+ recurseFolder(node, (childNode, filepath) => {
263
+ queue.add(async () => {
264
+ const succeeded = await writeFileMapperNode(accountId, filepath || '', childNode, mode, options);
265
+ if (succeeded === false) {
266
+ success = false;
267
+ logger_1.logger.debug((0, lang_1.i18n)(`${i18nKey}.errors.failedToFetchFile`, {
268
+ src: childNode.path,
269
+ dest: filepath || '',
270
+ }));
271
+ }
272
+ });
273
+ return success;
274
+ }, rootPath);
275
+ await queue.onIdle();
276
+ if (success) {
277
+ logger_1.logger.success((0, lang_1.i18n)(`${i18nKey}.completedFolderFetch`, {
278
+ src,
279
+ version: getAssetVersionIdentifier(options.assetVersion, src),
280
+ dest,
281
+ }));
282
+ }
283
+ else {
284
+ // TODO: Fix this exception. It is triggering the catch block so this error is being rewritten
285
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.incompleteFetch`, { src }));
286
+ }
287
+ }
288
+ catch (err) {
289
+ const error = err;
290
+ if ((0, errors_1.isTimeoutError)(error)) {
291
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.assetTimeout`), { cause: error });
292
+ }
293
+ else {
294
+ throw new Error((0, lang_1.i18n)(`${i18nKey}.errors.failedToFetchFolder`, { src, dest: destPath }), { cause: err });
295
+ }
296
+ }
297
+ }
298
+ /**
299
+ * Fetch a file/folder and write to local file system.
300
+ *
301
+ * @async
302
+ * @param {FileMapperInputArguments} input
303
+ * @returns {Promise}
304
+ */
305
+ async function downloadFileOrFolder(accountId, src, dest, mode, options = {}) {
306
+ if (!src) {
307
+ return;
308
+ }
309
+ const { isFile } = getTypeDataFromPath(src);
310
+ if (isFile) {
311
+ await downloadFile(accountId, src, dest, mode, options);
312
+ }
313
+ else {
314
+ await downloadFolder(accountId, src, dest, mode, options);
315
+ }
316
+ }
317
+ exports.downloadFileOrFolder = downloadFileOrFolder;
package/lib/fs.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { FileData } from '../types/Files';
2
+ export declare function getFileInfoAsync(dir: string, file: string): Promise<FileData>;
3
+ export declare function flattenAndRemoveSymlinks(filesData: Array<FileData>): Array<string>;
4
+ export declare function walk(dir: string): Promise<Array<string>>;
package/lib/fs.js ADDED
@@ -0,0 +1,71 @@
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.walk = exports.flattenAndRemoveSymlinks = exports.getFileInfoAsync = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const files_1 = require("../constants/files");
10
+ const FileSystemError_1 = require("../models/FileSystemError");
11
+ function getFileInfoAsync(dir, file) {
12
+ return new Promise((resolve, reject) => {
13
+ const filepath = path_1.default.join(dir, file);
14
+ fs_1.default.lstat(filepath, (error, stats) => {
15
+ if (error) {
16
+ reject(error);
17
+ }
18
+ let type = files_1.STAT_TYPES.FILE;
19
+ if (stats.isSymbolicLink()) {
20
+ type = files_1.STAT_TYPES.SYMBOLIC_LINK;
21
+ }
22
+ else if (stats.isDirectory()) {
23
+ type = files_1.STAT_TYPES.DIRECTORY;
24
+ }
25
+ resolve({ filepath, type });
26
+ });
27
+ });
28
+ }
29
+ exports.getFileInfoAsync = getFileInfoAsync;
30
+ function flattenAndRemoveSymlinks(filesData) {
31
+ return filesData.reduce((acc, fileData) => {
32
+ switch (fileData.type) {
33
+ case files_1.STAT_TYPES.FILE:
34
+ return acc.concat(fileData.filepath);
35
+ case files_1.STAT_TYPES.DIRECTORY:
36
+ return acc.concat(fileData.files || []);
37
+ case files_1.STAT_TYPES.SYMBOLIC_LINK:
38
+ return acc;
39
+ default:
40
+ return acc;
41
+ }
42
+ }, []);
43
+ }
44
+ exports.flattenAndRemoveSymlinks = flattenAndRemoveSymlinks;
45
+ const generateRecursiveFilePromise = async (dir, file) => {
46
+ return getFileInfoAsync(dir, file).then(fileData => {
47
+ return new Promise(resolve => {
48
+ if (fileData.type === files_1.STAT_TYPES.DIRECTORY) {
49
+ walk(fileData.filepath).then(files => {
50
+ resolve({ ...fileData, files });
51
+ });
52
+ }
53
+ else {
54
+ resolve(fileData);
55
+ }
56
+ });
57
+ });
58
+ };
59
+ async function walk(dir) {
60
+ function processFiles(files) {
61
+ return Promise.all(files.map(file => generateRecursiveFilePromise(dir, file)));
62
+ }
63
+ return fs_1.default.promises
64
+ .readdir(dir)
65
+ .then(processFiles)
66
+ .then(flattenAndRemoveSymlinks)
67
+ .catch(err => {
68
+ throw new FileSystemError_1.FileSystemError({ cause: err });
69
+ });
70
+ }
71
+ exports.walk = walk;