@shoper/cli 0.5.2-5 → 0.5.2-7

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 (96) hide show
  1. package/build/cli/auth/cli_auth_errors_factory.js +1 -1
  2. package/build/cli/auth/cli_auth_initializer.js +6 -1
  3. package/build/cli/auth/service/cli_auth_service.js +11 -2
  4. package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +1 -1
  5. package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +6 -1
  6. package/build/cli/auth/tokens/service/cli_auth_tokens_service.js +8 -1
  7. package/build/cli/class/base_command.js +15 -1
  8. package/build/cli/class/errors/file_system_errors_factory.js +3 -3
  9. package/build/cli/class/errors/http/http_errors_factory.js +2 -2
  10. package/build/cli/commands/auth/cli_auth_add_token_command.js +5 -0
  11. package/build/cli/commands/auth/cli_auth_list_tokens_command.js +20 -11
  12. package/build/cli/commands/auth/cli_auth_logout_command.js +5 -0
  13. package/build/cli/commands/auth/cli_auth_remove_token_command.js +5 -0
  14. package/build/cli/commands/auth/cli_auth_switch_token_command.js +8 -0
  15. package/build/cli/commands/cli_update_command.js +5 -0
  16. package/build/cli/core/cli_setup.js +11 -18
  17. package/build/cli/features/execution_context/execution_context_service.js +2 -0
  18. package/build/cli/features/version/service/cli_version_service.js +2 -2
  19. package/build/cli/hooks/authorization/ensure_authorization_hook.js +9 -2
  20. package/build/cli/hooks/ensure_cli_initialized_hook.js +1 -6
  21. package/build/cli/hooks/ensure_logs_flushed_hook.js +7 -0
  22. package/build/cli/index.js +0 -1
  23. package/build/cli/{features → utilities/features}/http_requester/http_client.js +2 -2
  24. package/build/cli/{features → utilities/features}/http_requester/http_requester_initializer.js +1 -1
  25. package/build/cli/utilities/features/logger/api/logger_api.js +28 -0
  26. package/build/cli/utilities/features/logger/logger_constants.js +7 -0
  27. package/build/cli/utilities/features/logger/logger_initializer.js +44 -0
  28. package/build/cli/utilities/features/logger/logs/app_error.js +14 -0
  29. package/build/cli/utilities/features/logger/logs/app_log.js +40 -0
  30. package/build/cli/{class/errors/app/app_error_constants.js → utilities/features/logger/logs/app_logs_constants.js} +1 -1
  31. package/build/cli/utilities/features/logger/service/logger_service.js +108 -0
  32. package/build/cli/utilities/features/logger/transports/log_object_map_transport.js +15 -22
  33. package/build/index.js +13 -2
  34. package/build/theme/class/archive/theme_archive.js +45 -0
  35. package/build/theme/{features/theme/utils/archive/theme_archive_utils_errors_factory.js → class/archive/theme_archive_errors_factory.js} +2 -2
  36. package/build/theme/class/checksums/theme_checksums.js +34 -52
  37. package/build/theme/class/checksums/theme_checksums_error_factory.js +3 -3
  38. package/build/theme/class/fetch_resources/fetch_resources.js +34 -4
  39. package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +1 -1
  40. package/build/theme/commands/delete/theme_delete_command.js +3 -2
  41. package/build/theme/commands/info/theme_info_command.js +3 -0
  42. package/build/theme/commands/init/theme_init_command.js +10 -1
  43. package/build/theme/commands/list/theme_list_command.js +22 -8
  44. package/build/theme/commands/publish/theme_publish_command.js +5 -1
  45. package/build/theme/commands/pull/theme_pull_command.js +18 -7
  46. package/build/theme/commands/push/theme_push_command.js +15 -21
  47. package/build/theme/commands/theme_verify_command.js +9 -4
  48. package/build/theme/commands/ui/theme_error.js +3 -3
  49. package/build/theme/features/theme/actions/service/theme_actions_service.js +42 -2
  50. package/build/theme/features/theme/actions/theme_actions_constants.js +1 -2
  51. package/build/theme/features/theme/actions/theme_actions_initializer.js +3 -1
  52. package/build/theme/features/theme/actions/theme_actions_utils.js +5 -31
  53. package/build/theme/features/theme/delete/service/theme_delete_service.js +12 -1
  54. package/build/theme/features/theme/delete/theme_delete_initalizer.js +6 -1
  55. package/build/theme/features/theme/fetch/service/theme_fetch_service.js +37 -8
  56. package/build/theme/features/theme/fetch/theme_fetch_initializer.js +3 -0
  57. package/build/theme/features/theme/init/service/theme_init_service.js +34 -8
  58. package/build/theme/features/theme/init/theme_init_initializer.js +4 -1
  59. package/build/theme/features/theme/merge/service/theme_merge_service.js +40 -6
  60. package/build/theme/features/theme/merge/theme_merge_initializer.js +3 -1
  61. package/build/theme/features/theme/push/api/theme_push_api.js +2 -2
  62. package/build/theme/features/theme/push/service/theme_push_service.js +59 -90
  63. package/build/theme/features/theme/push/theme_push_errors_factory.js +2 -2
  64. package/build/theme/features/theme/push/theme_push_initializer.js +3 -1
  65. package/build/theme/features/theme/push/theme_push_utils.js +3 -3
  66. package/build/theme/features/theme/utils/files_structure/theme_file_structure_errors_factory.js +9 -0
  67. package/build/theme/features/theme/utils/{files/theme_files_utils.js → files_structure/theme_files_structure_utils.js} +23 -34
  68. package/build/theme/features/theme/utils/hidden_directory/hidden_directory_utils.js +5 -2
  69. package/build/theme/features/theme/utils/meta_data/theme_meta_data_error_factory.js +1 -1
  70. package/build/theme/features/theme/utils/resources/theme_resources_with_id_directory_utils.js +5 -2
  71. package/build/theme/features/theme/verify/theme_verify_initializer.js +4 -3
  72. package/build/theme/features/theme/verify/verify/theme_verify_service.js +30 -18
  73. package/build/theme/features/themes/list/services/themes_list_service.js +36 -5
  74. package/build/theme/features/themes/list/themes_list_initializer.js +3 -1
  75. package/build/theme/hooks/ensure_theme_meta_data_untouched_hook.js +4 -2
  76. package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_hook.js +7 -2
  77. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +2 -3
  78. package/build/ui/hooks/stream_hook.js +26 -0
  79. package/build/utils/array_utils.js +0 -3
  80. package/build/utils/download_file/download_file_errors_factory.js +1 -1
  81. package/build/utils/download_file/download_file_utils.js +19 -1
  82. package/build/utils/fs/errors/stream_read_error.js +7 -5
  83. package/build/utils/fs/errors/stream_write_error.js +7 -5
  84. package/build/utils/fs/fs_utils.js +1 -1
  85. package/build/utils/get_api.js +9 -0
  86. package/build/utils/use_api.js +5 -0
  87. package/build/utils/zip/create_zip_utils.js +21 -9
  88. package/build/utils/zip/errors/create_zip_error.js +7 -5
  89. package/build/utils/zip/errors/open_zip_error.js +7 -5
  90. package/build/utils/zip/extract_zip_utils.js +90 -15
  91. package/oclif.config.js +2 -1
  92. package/package.json +13 -13
  93. package/build/cli/class/errors/app/app_error.js +0 -17
  94. package/build/theme/features/theme/utils/archive/theme_archive_utils.js +0 -24
  95. package/build/theme/features/theme/utils/files/them_files_constants.js +0 -1
  96. package/build/utils/fs/fs_constants.js +0 -6
@@ -1,4 +1,4 @@
1
- import { fileExists, isDirectory, readJSONFile, removeFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
1
+ import { readJSONFile, removeFile, writeJSONFile } from '../../../../../utils/fs/fs_utils.js';
2
2
  import { join, looksLikeDirectory, mapKeysPathsToWindowPlatform, toUnixPath } from '../../../../../utils/path_utils.js';
3
3
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
4
4
  import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_FILES_STRUCTURE_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
@@ -7,8 +7,7 @@ import { validateDirectory } from '../../../../utils/directory_validator/directo
7
7
  import path from 'node:path';
8
8
  import { THEME_FILES_LIST_FILE_NAME } from '../../push/theme_push_constants.js';
9
9
  import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
10
- import { FILE_STATES } from '../../../../../utils/fs/fs_constants.js';
11
- export class ThemeFilesUtils {
10
+ export class ThemeFilesStructureUtils {
12
11
  static async getThemeFilesStructure(themeDirectory) {
13
12
  const filesStructure = await readJSONFile(join(themeDirectory, SHOPER_THEME_METADATA_DIR, THEME_FILES_STRUCTURE_FILE_NAME));
14
13
  if (!isWindowsOs())
@@ -20,7 +19,7 @@ export class ThemeFilesUtils {
20
19
  await writeJSONFile(filePath, filesStructure);
21
20
  }
22
21
  static async getFilesPermissions(themeDirectory) {
23
- const fileStructure = await ThemeFilesUtils.getThemeFilesStructure(themeDirectory);
22
+ const fileStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDirectory);
24
23
  return Object.entries(fileStructure).reduce((acc, [key, value]) => {
25
24
  return {
26
25
  ...acc,
@@ -36,25 +35,14 @@ export class ThemeFilesUtils {
36
35
  });
37
36
  }
38
37
  static async getThemeRootDirectories(themeDirectory) {
39
- const filesStructure = await ThemeFilesUtils.getThemeFilesStructure(themeDirectory);
38
+ const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDirectory);
40
39
  return Object.keys(filesStructure).filter((path) => {
41
40
  return looksLikeDirectory(path);
42
41
  });
43
42
  }
44
43
  static mapFilesRecordsToFilesList(filesRecords, localFileNameToUploaded = {}) {
45
- let areAllSkinstoreFilesUnchanged = true;
46
- const filesList = filesRecords.reduce((acc, { fileGlob, fileName, state, actionKey }) => {
44
+ const mappedFilesRecords = filesRecords.reduce((acc, { fileGlob, fileName }) => {
47
45
  const name = localFileNameToUploaded[fileName] ?? fileName;
48
- if (state === FILE_STATES.deleted && actionKey === 'thumbnail') {
49
- return {
50
- ...acc,
51
- [fileGlob]: null
52
- };
53
- }
54
- if (actionKey === 'skinstore_files' && state !== FILE_STATES.unchanged)
55
- areAllSkinstoreFilesUnchanged = false;
56
- if (state === FILE_STATES.deleted || (state === FILE_STATES.unchanged && actionKey !== 'skinstore_files'))
57
- return acc;
58
46
  if (looksLikeDirectory(fileGlob)) {
59
47
  const existingFiles = acc[fileGlob] || [];
60
48
  return {
@@ -69,31 +57,32 @@ export class ThemeFilesUtils {
69
57
  };
70
58
  }
71
59
  }, {});
72
- if (areAllSkinstoreFilesUnchanged)
73
- delete filesList['skinstore/files'];
74
- return filesList;
60
+ /*
61
+ * Brzydki fix, poprawione w partial push na ładniej
62
+ */
63
+ if (!mappedFilesRecords['settings/thumbnail.jpg']) {
64
+ mappedFilesRecords['settings/thumbnail.jpg'] = null;
65
+ }
66
+ return mappedFilesRecords;
75
67
  }
76
68
  static async createAFilesListFile(themeRootDir, filesList) {
77
69
  if (!filesList || !Object.keys(filesList).length)
78
70
  return;
79
- const toUnixStyleFilesList = {};
80
- for (const [filePath, value] of Object.entries(filesList)) {
71
+ const toUnixStyleFilesList = Object.entries(filesList).reduce((acc, [filePath, value]) => {
81
72
  const unixPath = toUnixPath(filePath);
82
- const finalPath = (await fileExists(join(themeRootDir, filePath))) && (await isDirectory(join(themeRootDir, filePath)))
83
- ? `${unixPath}${path.posix.sep}`
84
- : unixPath;
85
- toUnixStyleFilesList[finalPath] = value;
86
- }
87
- await writeJSONFile(this.getFilesListFilePath(themeRootDir), toUnixStyleFilesList);
88
- }
89
- static getFilesListFilePath(themeRootDir) {
90
- return join(themeRootDir, THEME_FILES_LIST_FILE_NAME);
73
+ const finalPath = looksLikeDirectory(unixPath) ? `${unixPath}${path.posix.sep}` : unixPath;
74
+ return {
75
+ ...acc,
76
+ [finalPath]: value
77
+ };
78
+ }, {});
79
+ await writeJSONFile(join(themeRootDir, THEME_FILES_LIST_FILE_NAME), toUnixStyleFilesList);
91
80
  }
92
81
  static async removeAFilesListFile(themeRootDir) {
93
- await removeFile(this.getFilesListFilePath(themeRootDir));
82
+ await removeFile(join(themeRootDir, THEME_FILES_LIST_FILE_NAME));
94
83
  }
95
84
  static async updateFilesStructure(themeDir) {
96
- const fileStructure = await ThemeFilesUtils.getThemeFilesStructure(themeDir);
85
+ const fileStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDir);
97
86
  const checksumsFiles = [
98
87
  `${SHOPER_THEME_METADATA_DIR}/${THEME_INITIAL_CHECKSUMS_FILE_NAME}`,
99
88
  `${SHOPER_THEME_METADATA_DIR}/${THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME}`,
@@ -126,6 +115,6 @@ export class ThemeFilesUtils {
126
115
  }
127
116
  };
128
117
  });
129
- await ThemeFilesUtils.writeThemeFilesStructure(themeDir, fileStructure);
118
+ await ThemeFilesStructureUtils.writeThemeFilesStructure(themeDir, fileStructure);
130
119
  }
131
120
  }
@@ -5,9 +5,12 @@ import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_conts
5
5
  import { computeFileChecksum } from '../../../../../utils/checksums/checksums_utils.js';
6
6
  import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
7
7
  export class HiddenDirectoryUtils {
8
- static async ensureFilesInsideThemeMetaDataDirectoryUntouched(themeDirectory) {
8
+ static async ensureFilesInsideThemeMetaDataDirectoryUntouched(themeDirectory, logger) {
9
9
  const themeMetadataPath = this.getThemeHiddenDirectoryPath(themeDirectory);
10
- const themeChecksums = new ThemeChecksums(themeDirectory);
10
+ const themeChecksums = new ThemeChecksums({
11
+ themeDir: themeDirectory,
12
+ loggerApi: logger
13
+ });
11
14
  if (!(await themeChecksums.verify()))
12
15
  throw new Error('Theme checksum file is not valid');
13
16
  const filesNames = (await getAllFilesNamesInside(themeMetadataPath)).filter((fileName) => fileName !== THEME_CURRENT_CHECKSUMS_FILE_NAME &&
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
1
+ import { AppError } from '../../../../../cli/utilities/features/logger/logs/app_error.js';
2
2
  import { THEME_WORK_URL_MISMATCH_ERROR } from './theme_meta_data_constants.js';
3
3
  export class ThemeMetaDataErrorFactory {
4
4
  static createThemeWorkUrlMismatchError(executionUrl, themeWorkUrl) {
@@ -5,7 +5,7 @@ import { fileExists, readJSONFile, renameFile } from '../../../../../utils/fs/fs
5
5
  import { join } from '../../../../../utils/path_utils.js';
6
6
  import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
7
7
  export class ThemeResourcesWithIdDirectoryUtils {
8
- static async updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localResourcesDir, remoteResourcesDir, remoteThemeDir) {
8
+ static async updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localResourcesDir, remoteResourcesDir, remoteThemeDir, loggerApi) {
9
9
  const localThemeTree = new FSTree({
10
10
  entries: walkSync.entries(localResourcesDir, {
11
11
  globs: ['*/'],
@@ -37,7 +37,10 @@ export class ThemeResourcesWithIdDirectoryUtils {
37
37
  /**
38
38
  * If these become performance bottlenecks, we can consider computing checksums only for the changed directories.
39
39
  */
40
- await new ThemeChecksums(remoteThemeDir).updateAllChecksums();
40
+ await new ThemeChecksums({
41
+ themeDir: remoteThemeDir,
42
+ loggerApi
43
+ }).updateAllChecksums();
41
44
  }
42
45
  }
43
46
  static async _getResourceIdToFilePathMap(entries) {
@@ -1,12 +1,13 @@
1
- import { FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME, SyncFeatureInitializer } from '@dreamcommerce/star_core';
1
+ import { FEATURE_CORES_TYPES, SyncFeatureInitializer } from '@dreamcommerce/star_core';
2
2
  import { ThemeVerifyApi } from './api/theme_verify_api.js';
3
3
  import { THEME_VERIFY_FEATURE_NAME } from './theme_verify_constants.js';
4
4
  import { ThemeVerifyService } from './verify/theme_verify_service.js';
5
+ import { LOGGER_API_NAME } from '../../../../cli/utilities/features/logger/logger_constants.js';
5
6
  export class ThemeVerifyInitializer extends SyncFeatureInitializer {
6
7
  static featureName = THEME_VERIFY_FEATURE_NAME;
7
8
  init() {
8
- const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
9
- const service = new ThemeVerifyService();
9
+ const loggerApi = this.getApiSync(LOGGER_API_NAME);
10
+ const service = new ThemeVerifyService({ loggerApi });
10
11
  return {
11
12
  cores: [
12
13
  {
@@ -3,29 +3,40 @@ import { ThemePublishUtils } from '../../skinstore/theme_publish_utils.js';
3
3
  import { ThemePushErrorsFactory } from '../../push/theme_push_errors_factory.js';
4
4
  import { join } from '../../../../../utils/path_utils.js';
5
5
  import { v4 as uuid } from 'uuid';
6
- import { ThemeArchiveUtils } from '../../utils/archive/theme_archive_utils.js';
7
- import { ThemeActionsUtils } from '../../actions/theme_actions_utils.js';
8
- import { ThemeFilesUtils } from '../../utils/files/theme_files_utils.js';
6
+ import { ThemeArchive } from '../../../../class/archive/theme_archive.js';
9
7
  import { THEME_WILDCARD_ACTION_NAME } from '../../actions/service/theme_actions_service_constants.js';
10
8
  import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
11
- import { FILE_STATES } from '../../../../../utils/fs/fs_constants.js';
9
+ import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
10
+ import { ThemeActionsUtils } from '../../actions/theme_actions_utils.js';
11
+ import { ArrayUtils } from '@dreamcommerce/utilities';
12
12
  export class ThemeVerifyService {
13
+ #loggerApi;
14
+ constructor({ loggerApi }) {
15
+ this.#loggerApi = loggerApi;
16
+ }
13
17
  async verifyTheme({ verifyAction, executionContext, credentials, themeChecksums, filesStructure, themeFilesUploadApi }) {
18
+ this.#loggerApi.info('Verifying theme.');
14
19
  const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
20
+ this.#loggerApi.debug('Temporary directory created.', { details: { path: tmpDir } });
15
21
  const themeRootDir = executionContext.themeRootDir;
16
22
  if (await themeChecksums.hasThemeFileBeenCreated(ThemePublishUtils.getSkinStoreSettingsFilePath(themeRootDir)))
17
23
  throw ThemePushErrorsFactory.createErrorWhilePushingUnpublishedThemeWithSkinstoreData(credentials.shopUrl);
18
24
  try {
19
- //TODO to do api?
25
+ this.#loggerApi.debug('Getting file records from action data.');
20
26
  const filesRecords = await ThemeActionsUtils.getFilesRecordsFromActionData({
21
27
  themeRootDir,
22
28
  themeAction: verifyAction,
23
- filesStructure,
24
- themeChecksums
29
+ filesStructure
25
30
  });
26
- const filesToVerify = filesRecords.filter(({ state }) => [FILE_STATES.modified, FILE_STATES.created].includes(state));
31
+ this.#loggerApi.debug('Filtering for modified or not created files to verify.');
32
+ const filesToVerify = await ArrayUtils.asyncFilter(filesRecords, async ({ path }) => (await themeChecksums.hasThemeFileBeenModified(path)) || !(await themeChecksums.hasThemeFileBeenCreated(path)));
33
+ this.#loggerApi.debug('Files to verify determined.', { details: { count: filesToVerify.length } });
27
34
  if (filesToVerify.length) {
35
+ this.#loggerApi.info(`Verifying ${filesToVerify.length} theme files.`);
28
36
  const { rejectedImageData } = await themeFilesUploadApi.uploadFiles(filesToVerify);
37
+ this.#loggerApi.debug('Individual files verification finished.', {
38
+ details: { rejectedCount: rejectedImageData.length }
39
+ });
29
40
  if (rejectedImageData.length)
30
41
  return {
31
42
  isSuccess: false,
@@ -34,28 +45,29 @@ export class ThemeVerifyService {
34
45
  }
35
46
  await this._createFilesList(themeRootDir, filesToVerify);
36
47
  const themeArchivePath = join(tmpDir, `${uuid()}.zip`);
37
- await ThemeArchiveUtils.create({
48
+ this.#loggerApi.info('Creating theme archive for verification.');
49
+ await new ThemeArchive(themeRootDir).createFullArchive({
38
50
  dist: themeArchivePath,
39
- rootDir: themeRootDir,
40
- files: await ThemeActionsUtils.getFilesThatMatchesAction({
41
- actionValue: THEME_WILDCARD_ACTION_NAME,
42
- actionType: THEME_ACTIONS_TYPES.push,
43
- filesStructure,
44
- rootDir: themeRootDir
45
- })
51
+ actionValue: THEME_WILDCARD_ACTION_NAME,
52
+ actionType: THEME_ACTIONS_TYPES.push,
53
+ logger: this.#loggerApi
46
54
  });
55
+ this.#loggerApi.info('Theme archive created.');
47
56
  const { isSuccess, messages } = await themeFilesUploadApi.uploadArchive({
48
57
  action: verifyAction,
49
58
  themeArchivePath,
50
59
  credentials
51
60
  });
61
+ this.#loggerApi.info('Theme archive verification finished.');
52
62
  return { isSuccess, messages };
53
63
  }
54
64
  finally {
55
- await ThemeFilesUtils.removeAFilesListFile(themeRootDir);
65
+ this.#loggerApi.debug('Cleaning up files list.');
66
+ await ThemeFilesStructureUtils.removeAFilesListFile(themeRootDir);
56
67
  }
57
68
  }
58
69
  async _createFilesList(themeRootDir, filesRecords) {
59
- await ThemeFilesUtils.createAFilesListFile(themeRootDir, ThemeFilesUtils.mapFilesRecordsToFilesList(filesRecords));
70
+ this.#loggerApi.debug('Creating filesList.json for the archive.');
71
+ await ThemeFilesStructureUtils.createAFilesListFile(themeRootDir, ThemeFilesStructureUtils.mapFilesRecordsToFilesList(filesRecords));
60
72
  }
61
73
  }
@@ -4,20 +4,38 @@ import { HttpErrorsFactory } from '../../../../../cli/class/errors/http/http_err
4
4
  import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/download_file_errors_factory.js';
5
5
  export class ThemesListService {
6
6
  #httpApi;
7
- constructor(httpApi) {
7
+ #loggerApi;
8
+ constructor(httpApi, loggerApi) {
8
9
  this.#httpApi = httpApi;
10
+ this.#loggerApi = loggerApi;
9
11
  }
10
12
  async getThemes({ shopUrl }) {
13
+ this.#loggerApi.info('Fetching themes list.', {
14
+ details: {
15
+ shopUrl
16
+ }
17
+ });
11
18
  try {
12
19
  const { response: request } = this.#httpApi.getThemes(shopUrl);
13
20
  const response = await request;
14
- if (response?.status !== STATUS_CODES.ok)
21
+ if (response?.status !== STATUS_CODES.ok) {
22
+ this.#loggerApi.debug('Failed to fetch themes list.', {
23
+ details: {
24
+ status: response?.status
25
+ }
26
+ });
15
27
  return;
16
- //TODO baseHttpApi + model mapper
17
- return response?.data.map(({ _links, ...rest }) => new ThemeMetaData({
28
+ }
29
+ const themes = response?.data.map(({ _links, ...rest }) => new ThemeMetaData({
18
30
  ...rest,
19
31
  links: _links
20
32
  }));
33
+ this.#loggerApi.info('Successfully fetched themes list.', {
34
+ details: {
35
+ count: themes.length
36
+ }
37
+ });
38
+ return themes;
21
39
  }
22
40
  catch (err) {
23
41
  switch (err.response?.status) {
@@ -35,9 +53,22 @@ export class ThemesListService {
35
53
  }
36
54
  }
37
55
  async getTheme({ themeId, shopUrl }) {
56
+ this.#loggerApi.debug('Getting a specific theme from list.', {
57
+ details: {
58
+ themeId,
59
+ shopUrl
60
+ }
61
+ });
38
62
  const themes = await this.getThemes({ shopUrl });
39
63
  if (!themes)
40
64
  return;
41
- return themes.find((theme) => String(theme.skinId) === themeId);
65
+ const theme = themes.find((theme) => String(theme.skinId) === themeId);
66
+ this.#loggerApi.debug(theme ? 'Theme found.' : 'Theme not found.', {
67
+ details: {
68
+ themeId,
69
+ found: !!theme
70
+ }
71
+ });
72
+ return theme;
42
73
  }
43
74
  }
@@ -3,11 +3,13 @@ import { ThemesListApi } from './api/themes_list_api.js';
3
3
  import { FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME, SyncFeatureInitializer } from '@dreamcommerce/star_core';
4
4
  import { THEMES_LIST_FEATURE_NAME } from './themes_list_constants.js';
5
5
  import { ThemesListHttpApi } from './http/themes_list_http_api.js';
6
+ import { LOGGER_API_NAME } from '../../../../cli/utilities/features/logger/logger_constants.js';
6
7
  export class ThemesListInitializer extends SyncFeatureInitializer {
7
8
  static featureName = THEMES_LIST_FEATURE_NAME;
8
9
  init() {
9
10
  const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
10
- const service = new ThemesListService(new ThemesListHttpApi(httpApi));
11
+ const loggerApi = this.getApiSync(LOGGER_API_NAME);
12
+ const service = new ThemesListService(new ThemesListHttpApi(httpApi), loggerApi);
11
13
  return {
12
14
  cores: [
13
15
  {
@@ -1,13 +1,15 @@
1
- import { useApi } from '../../cli/hooks/ensure_cli_initialized_hook.js';
2
1
  import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../cli/features/execution_context/execution_context_constants.js';
3
2
  import { HiddenDirectoryUtils } from '../features/theme/utils/hidden_directory/hidden_directory_utils.js';
3
+ import { LOGGER_API_NAME } from '../../cli/utilities/features/logger/logger_constants.js';
4
+ import { useApi } from '../../utils/use_api.js';
4
5
  const ensureThemeMetaDataUntouched = async () => {
5
6
  const executionContextApi = useApi(EXECUTION_CONTEXT_API_NAME);
6
7
  const executionContext = await executionContextApi.getExecutionContext();
7
8
  if (executionContext.type !== EXECUTION_CONTEXTS.theme)
8
9
  return;
10
+ const loggerApi = useApi(LOGGER_API_NAME);
9
11
  try {
10
- await HiddenDirectoryUtils.ensureFilesInsideThemeMetaDataDirectoryUntouched(executionContext.themeRootDir);
12
+ await HiddenDirectoryUtils.ensureFilesInsideThemeMetaDataDirectoryUntouched(executionContext.themeRootDir, loggerApi);
11
13
  }
12
14
  catch (err) {
13
15
  console.error(err);
@@ -1,7 +1,8 @@
1
1
  import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
2
- import { useApi } from '../../../cli/hooks/ensure_cli_initialized_hook.js';
3
2
  import { THEME_COMMANDS_THAT_REQUIRES_UP_TO_DATE_CHECKSUMS } from './ensure_theme_current_checksums_up_to_date_constants.js';
4
3
  import { ThemeChecksums } from '../../class/checksums/theme_checksums.js';
4
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
5
+ import { useApi } from '../../../utils/use_api.js';
5
6
  export const ensureThemeChecksumsUpToDate = async ({ Command }) => {
6
7
  if (!THEME_COMMANDS_THAT_REQUIRES_UP_TO_DATE_CHECKSUMS.includes(Command.id))
7
8
  return;
@@ -9,10 +10,14 @@ export const ensureThemeChecksumsUpToDate = async ({ Command }) => {
9
10
  const executionContext = await executionContextApi.getExecutionContext();
10
11
  if (executionContext.type !== EXECUTION_CONTEXTS.theme)
11
12
  return;
13
+ const loggerApi = useApi(LOGGER_API_NAME);
12
14
  /**
13
15
  * Naive solution, recalculate checksums every time a command based on checksums calculation is executed;
14
16
  * If performance becomes an issue, we can implement a more sophisticated solution, eg. recalculate checksums only when files in the theme directory have changed.
15
17
  */
16
- await new ThemeChecksums(executionContext.themeRootDir).updateCurrentChecksums();
18
+ await new ThemeChecksums({
19
+ themeDir: executionContext.themeRootDir,
20
+ loggerApi
21
+ }).updateCurrentChecksums();
17
22
  };
18
23
  export default ensureThemeChecksumsUpToDate;
@@ -1,10 +1,10 @@
1
- import { useApi } from '../../../cli/hooks/ensure_cli_initialized_hook.js';
2
1
  import { THEME_ACTIONS_API_NAME } from '../../features/theme/actions/theme_actions_constants.js';
3
2
  import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_constants.js';
4
3
  import { THEME_COMMANDS_THAT_REQUIRED_ACTIONS_LIST } from './ensure_themes_actions_hook_constants.js';
5
4
  import { CLI_AUTH_TOKENS_API_NAME } from '../../../cli/auth/tokens/cli_auth_tokens_constants.js';
6
5
  import { promptForToken } from '../../../cli/commands/utils/prompt_for_token_utils.js';
7
6
  import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
7
+ import { useApi } from '../../../utils/use_api.js';
8
8
  const ensureThemesActionsHook = async ({ Command, argv }) => {
9
9
  if (!THEME_COMMANDS_THAT_REQUIRED_ACTIONS_LIST.includes(Command.id))
10
10
  return;
@@ -38,8 +38,7 @@ const ensureThemesActionsHook = async ({ Command, argv }) => {
38
38
  });
39
39
  }
40
40
  else {
41
- console.error(err);
42
- process.exit(1);
41
+ throw err;
43
42
  }
44
43
  }
45
44
  };
@@ -0,0 +1,26 @@
1
+ import { useEffect, useState } from 'react';
2
+ /**
3
+ * A React hook that subscribes to a Readable stream and returns an array of data chunks.
4
+ * @param stream The readable stream to listen to.
5
+ * @returns An array of strings received from the stream.
6
+ */
7
+ export function useStream(stream) {
8
+ const [data, setData] = useState([]);
9
+ useEffect(() => {
10
+ // Do nothing if the stream is not provided
11
+ if (!stream) {
12
+ return;
13
+ }
14
+ const handleData = (chunk) => {
15
+ // Append the new data chunk to the state
16
+ setData((prevData) => [...prevData, chunk.toString()]);
17
+ };
18
+ // Subscribe to the 'data' event
19
+ stream.on('data', handleData);
20
+ // Return a cleanup function to be called on component unmount
21
+ return () => {
22
+ stream.removeListener('data', handleData);
23
+ };
24
+ }, [stream]); // Re-run the effect if the stream instance changes
25
+ return data;
26
+ }
@@ -4,6 +4,3 @@ export const asyncFilter = async (array, callback) => {
4
4
  return array.filter((_v, index) => results[index]);
5
5
  });
6
6
  };
7
- export const asyncMap = async (array, callback) => {
8
- return Promise.all(array.map(callback));
9
- };
@@ -1,4 +1,4 @@
1
- import { AppError } from '../../cli/class/errors/app/app_error.js';
1
+ import { AppError } from '../../cli/utilities/features/logger/logs/app_error.js';
2
2
  export class DownloadFileErrorsFactory {
3
3
  static downloadError(status) {
4
4
  return new AppError({
@@ -5,8 +5,13 @@ import { basename, extname, join, parse } from '../path_utils.js';
5
5
  import { FileSystemErrorsFactory } from '../../cli/class/errors/file_system_errors_factory.js';
6
6
  import { HttpErrorsFactory } from '../../cli/class/errors/http/http_errors_factory.js';
7
7
  import { DownloadFileErrorsFactory } from './download_file_errors_factory.js';
8
- export const downloadFile = async ({ dist, request }) => {
8
+ export const downloadFile = async ({ dist, request, logger }) => {
9
9
  try {
10
+ logger.debug('Starting file download', {
11
+ details: {
12
+ dist
13
+ }
14
+ });
10
15
  const resp = (await request);
11
16
  if (!resp)
12
17
  throw resp;
@@ -17,6 +22,12 @@ export const downloadFile = async ({ dist, request }) => {
17
22
  resp.data.pipe(file);
18
23
  return new Promise((resolve, reject) => {
19
24
  file.on('finish', () => {
25
+ logger.debug('File download completed', {
26
+ details: {
27
+ dist,
28
+ filename
29
+ }
30
+ });
20
31
  resolve({
21
32
  filename,
22
33
  ext: extname(filename),
@@ -24,6 +35,13 @@ export const downloadFile = async ({ dist, request }) => {
24
35
  });
25
36
  });
26
37
  file.on('error', (err) => {
38
+ logger.error('Error downloading file', {
39
+ error: err,
40
+ details: {
41
+ dist,
42
+ filename
43
+ }
44
+ });
27
45
  if (err.code === 'ENOSPC')
28
46
  reject(FileSystemErrorsFactory.createDiskFullError());
29
47
  reject(DownloadFileErrorsFactory.downloadError(err.response.status));
@@ -1,11 +1,13 @@
1
- import { AppError } from '../../../cli/class/errors/app/app_error.js';
1
+ import { AppError } from '../../../cli/utilities/features/logger/logs/app_error.js';
2
2
  export class StreamReadError extends AppError {
3
- constructor({ filePath, details, stack }) {
3
+ constructor({ filePath, error }) {
4
4
  super({
5
5
  code: 'STREAM_READ_ERROR',
6
- message: `Error while reading stream for file: ${filePath}`,
7
- details,
8
- stack
6
+ message: `Error while reading stream for file`,
7
+ details: {
8
+ filePath
9
+ },
10
+ error
9
11
  });
10
12
  }
11
13
  }
@@ -1,11 +1,13 @@
1
- import { AppError } from '../../../cli/class/errors/app/app_error.js';
1
+ import { AppError } from '../../../cli/utilities/features/logger/logs/app_error.js';
2
2
  export class StreamWriteError extends AppError {
3
- constructor({ filePath, details, stack }) {
3
+ constructor({ filePath, error }) {
4
4
  super({
5
5
  code: 'STREAM_WRITE_ERROR',
6
- message: `Error while writing to stream for file: ${filePath}`,
7
- details,
8
- stack
6
+ message: `Error while writing to stream for file`,
7
+ details: {
8
+ filePath
9
+ },
10
+ error
9
11
  });
10
12
  }
11
13
  }
@@ -100,7 +100,7 @@ export const getAllFilesAndDirectoriesInside = async (path, options) => {
100
100
  withFileTypes
101
101
  });
102
102
  };
103
- export const getAllDirectoriesNamesInside = async (path, options = { recursive: false, hidden: false }) => {
103
+ export const getAllDirectoriesNamesInside = async (path, options) => {
104
104
  const { recursive = true, hidden = true } = options;
105
105
  const files = await fsPromises.readdir(path, {
106
106
  recursive,
@@ -0,0 +1,9 @@
1
+ import { API_RESOLVER_QUERIES, AppError, getStarCoreEnvironment, QueryMessage } from '@dreamcommerce/star_core';
2
+ export const getApiSync = (apiName) => {
3
+ const { queryBus } = getStarCoreEnvironment();
4
+ const api = queryBus.executeSync(new QueryMessage(API_RESOLVER_QUERIES.getApiSync, apiName));
5
+ if (!api) {
6
+ throw new AppError(`${apiName} hasn't been registered`);
7
+ }
8
+ return api;
9
+ };
@@ -0,0 +1,5 @@
1
+ import { API_RESOLVER_QUERIES, getStarCoreEnvironment, QueryMessage } from '@dreamcommerce/star_core';
2
+ export function useApi(apiName) {
3
+ const { queryBus } = getStarCoreEnvironment();
4
+ return queryBus.executeSync(new QueryMessage(API_RESOLVER_QUERIES.getApiSync, apiName));
5
+ }