@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
@@ -16,6 +16,7 @@ import { ThemeDeletedSuccessfully } from './ui/theme_deleted_successfully.js';
16
16
  import { ThemeDeletionWarning } from './ui/theme_deletion_warning.js';
17
17
  import { promptConfirmation } from '../../../ui/prompts/prompt_confirmation.js';
18
18
  import { ThemeError } from '../ui/theme_error.js';
19
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
19
20
  export class ThemeDeleteCommand extends BaseThemeCommand {
20
21
  static summary = 'Permanently deletes the specified theme from your store.';
21
22
  static description = 'This action cannot be undone, so make sure you really want to remove this theme.\n\nYou can run this command from a specific theme directory (ID not needed) or outside any theme directory (theme ID required).';
@@ -37,6 +38,7 @@ export class ThemeDeleteCommand extends BaseThemeCommand {
37
38
  const themeId = this.args.id;
38
39
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
39
40
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
41
+ const loggerApi = this.getApi(LOGGER_API_NAME);
40
42
  const credentials = cliAuthApi.getCredentials();
41
43
  if (!credentials) {
42
44
  renderOnce(React.createElement(MissingCredentialsError, null));
@@ -86,11 +88,10 @@ export class ThemeDeleteCommand extends BaseThemeCommand {
86
88
  if (!resp?.isSuccess)
87
89
  return;
88
90
  renderOnce(React.createElement(ThemeDeletedSuccessfully, null));
89
- return;
90
91
  }
91
92
  catch (err) {
93
+ loggerApi.error('Error executing theme delete command', { error: err });
92
94
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
93
- return;
94
95
  }
95
96
  }
96
97
  }
@@ -15,6 +15,7 @@ import { ThemeInfoCommandUtils } from './theme_info_command_utils.js';
15
15
  import { InvalidThemeIdError } from '../ui/invalid_theme_id.js';
16
16
  import { Box } from '../../../ui/box.js';
17
17
  import { ThemeError } from '../ui/theme_error.js';
18
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
18
19
  export class ThemeInfoCommand extends BaseThemeCommand {
19
20
  static summary = 'View details about the current theme.';
20
21
  static description = 'Displays key information about the theme you’re working on — including its ID, name, description (if provided), and status.\n\nYou can run this command from a specific theme directory (ID not needed) or outside any theme directory (theme ID required).';
@@ -36,6 +37,7 @@ export class ThemeInfoCommand extends BaseThemeCommand {
36
37
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
37
38
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
38
39
  const themesListApi = this.getApi(THEMES_LIST_API_NAME);
40
+ const loggerApi = this.getApi(LOGGER_API_NAME);
39
41
  const credentials = cliAuthApi.getCredentials();
40
42
  if (!credentials) {
41
43
  renderOnce(React.createElement(MissingCredentialsError, null));
@@ -70,6 +72,7 @@ export class ThemeInfoCommand extends BaseThemeCommand {
70
72
  this._displayThemeInfo(theme);
71
73
  }
72
74
  catch (err) {
75
+ loggerApi.error('An error occurred while fetching theme info.', { error: err });
73
76
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
74
77
  }
75
78
  }
@@ -15,6 +15,7 @@ import { Text } from '../../../ui/text.js';
15
15
  import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
16
16
  import { Box } from '../../../ui/box.js';
17
17
  import { ThemeError } from '../ui/theme_error.js';
18
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
18
19
  export class ThemeInitCommand extends BaseThemeCommand {
19
20
  static summary = 'Creates a copy of an existing theme by duplicating it.';
20
21
  static description = 'The new theme will be named after the source theme with a "Copy" suffix and an incremental number.\n\nYou must run this command from the root directory (not inside any theme folder) and provide the ID of the theme you want to duplicate.';
@@ -38,6 +39,7 @@ export class ThemeInitCommand extends BaseThemeCommand {
38
39
  const themeInitApi = this.getApi(THEME_INIT_API_NAME);
39
40
  const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
40
41
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
42
+ const loggerApi = this.getApi(LOGGER_API_NAME);
41
43
  const credentials = cliAuthApi.getCredentials();
42
44
  if (!credentials) {
43
45
  renderOnce(React.createElement(MissingCredentialsError, null));
@@ -64,12 +66,19 @@ export class ThemeInitCommand extends BaseThemeCommand {
64
66
  return;
65
67
  }
66
68
  spinner = ora('Creating theme...').start();
67
- const { themeId: createdThemeId, themeName } = await themeInitApi.initTheme({ action: copyAction, credentials });
69
+ const { themeId: createdThemeId, themeName } = await themeInitApi.initTheme({
70
+ action: copyAction,
71
+ credentials,
72
+ sourceThemeId: themeId
73
+ });
68
74
  spinner.stop();
69
75
  renderOnce(React.createElement(ThemeCreatedSuccess, { createdThemeId: createdThemeId, themeName: themeName }));
70
76
  }
71
77
  catch (err) {
72
78
  spinner?.stop();
79
+ loggerApi.error('Error during theme init command execution', {
80
+ error: err
81
+ });
73
82
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
74
83
  //TODO analyze why on nodejs v22 this command does not exit properly, even all promises are resolved
75
84
  this.exit();
@@ -4,22 +4,36 @@ import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_constants.js';
4
4
  import { renderOnce } from '../../../ui/ui_utils.js';
5
5
  import { Info } from '../../../ui/message_box/info.js';
6
6
  import React from 'react';
7
- import { Table } from '../../../ui/table/table.js';
7
+ import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_credentials_error.js';
8
+ import { ThemeError } from '../ui/theme_error.js';
9
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
8
10
  import { ThemeListCommandUtils } from './theme_list_command_utils.js';
11
+ import { Table } from '../../../ui/table/table.js';
9
12
  export class ThemeListCommand extends BaseThemeCommand {
10
13
  static summary = 'Displays a list of all themes available in your store, including their IDs, names, and statuses (active/inactive).';
11
14
  static description = 'Use this to check which theme is now active in your store.';
12
15
  async run() {
13
- const ThemesListApi = this.getApi(THEMES_LIST_API_NAME);
16
+ const themesListApi = this.getApi(THEMES_LIST_API_NAME);
17
+ const loggerApi = this.getApi(LOGGER_API_NAME);
14
18
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
15
19
  const credentials = cliAuthApi.getCredentials();
16
- if (!credentials)
17
- this.error('Credentials not found. Please authorize first.');
18
- const themes = await ThemesListApi.getThemes(credentials);
19
- if (!themes?.length) {
20
- renderOnce(React.createElement(Info, { header: "No themes found for this store." }));
20
+ if (!credentials) {
21
+ renderOnce(React.createElement(MissingCredentialsError, null));
21
22
  return;
22
23
  }
23
- renderOnce(React.createElement(Table, { data: ThemeListCommandUtils.mapThemeListToTableData(themes) }));
24
+ try {
25
+ const themes = await themesListApi.getThemes(credentials);
26
+ if (!themes?.length) {
27
+ renderOnce(React.createElement(Info, { header: "No themes found for this store." }));
28
+ return;
29
+ }
30
+ renderOnce(React.createElement(Table, { data: ThemeListCommandUtils.mapThemeListToTableData(themes) }));
31
+ }
32
+ catch (err) {
33
+ loggerApi.error('Error while listing themes:', {
34
+ error: err
35
+ });
36
+ renderOnce(React.createElement(ThemeError, { err: err }));
37
+ }
24
38
  }
25
39
  }
@@ -10,6 +10,7 @@ import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
10
10
  import { THEME_SKINSTORE_API_NAME } from '../../features/theme/skinstore/theme_publish_constants.js';
11
11
  import { Form } from '../../../cli/features/controls/ui/form.js';
12
12
  import { ThemeError } from '../ui/theme_error.js';
13
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
13
14
  export class ThemePublishCommand extends BaseThemeCommand {
14
15
  static summary = 'Permanently deletes the specified theme from your store.';
15
16
  static description = 'This action cannot be undone, so make sure you really want to remove this theme.\n\nYou can run this command from a specific theme directory (ID not needed) or outside any theme directory (theme ID required).';
@@ -31,6 +32,7 @@ export class ThemePublishCommand extends BaseThemeCommand {
31
32
  async run() {
32
33
  const themeId = this.args.id;
33
34
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
35
+ const loggerApi = this.getApi(LOGGER_API_NAME);
34
36
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
35
37
  const credentials = cliAuthApi.getCredentials();
36
38
  if (!credentials) {
@@ -69,8 +71,10 @@ export class ThemePublishCommand extends BaseThemeCommand {
69
71
  });
70
72
  }
71
73
  catch (err) {
74
+ loggerApi.error('Theme publish command error:', {
75
+ error: err
76
+ });
72
77
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
73
- return;
74
78
  }
75
79
  }
76
80
  }
@@ -25,7 +25,7 @@ import { directoryExists } from '../../../utils/fs/fs_utils.js';
25
25
  import { ThemeMetaDataUtils } from '../../features/theme/utils/meta_data/theme_meta_data_utils.js';
26
26
  import { ThemeChecksums } from '../../class/checksums/theme_checksums.js';
27
27
  import { ThemeError } from '../ui/theme_error.js';
28
- import { MODULES_DIRECTORY_NAME } from '../../features/theme/theme_constants.js'; //TODO jak jest error w pullu wowczas usuwamy docelowo pociagniety skin
28
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
29
29
  //TODO jak jest error w pullu wowczas usuwamy docelowo pociagniety skin
30
30
  export class ThemePullCommand extends BaseThemeCommand {
31
31
  static summary = 'Downloads the current version of your theme from the store and overwrites your local theme files.';
@@ -61,6 +61,7 @@ export class ThemePullCommand extends BaseThemeCommand {
61
61
  const themeFetchApi = this.getApi(THEME_FETCH_API_NAME);
62
62
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
63
63
  const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
64
+ const loggerApi = this.getApi(LOGGER_API_NAME);
64
65
  const credentials = cliAuthApi.getCredentials();
65
66
  if (!credentials) {
66
67
  renderOnce(React.createElement(MissingCredentialsError, null));
@@ -86,12 +87,19 @@ export class ThemePullCommand extends BaseThemeCommand {
86
87
  themeActionsApi,
87
88
  fetchType: this.flags.type,
88
89
  executionContext,
89
- credentials
90
+ credentials,
91
+ loggerApi
90
92
  });
91
93
  }
92
94
  }
93
95
  catch (err) {
94
96
  this.#spinner?.stop();
97
+ loggerApi.error('Error occurred during theme pull operation', {
98
+ error: err,
99
+ details: {
100
+ executionContext
101
+ }
102
+ });
95
103
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
96
104
  }
97
105
  }
@@ -125,7 +133,7 @@ export class ThemePullCommand extends BaseThemeCommand {
125
133
  this.#spinner.stop();
126
134
  renderOnce(React.createElement(ThemePulledSuccess, null));
127
135
  }
128
- async _pullThemeIntoExistingOne({ themeId, themeFetchApi, themeActionsApi, fetchType, executionContext, credentials }) {
136
+ async _pullThemeIntoExistingOne({ themeId, themeFetchApi, themeActionsApi, fetchType, executionContext, credentials, loggerApi }) {
129
137
  //TODO move these logi somvewhere else?
130
138
  await ThemeMetaDataUtils.ensureThemeWorkUrlMatch(executionContext.themeRootDir, credentials.shopUrl);
131
139
  const pullAction = themeActionsApi.getThemeAction({
@@ -152,14 +160,17 @@ export class ThemePullCommand extends BaseThemeCommand {
152
160
  dist: tmpDir
153
161
  }
154
162
  });
155
- const localModulesPath = join(executionContext.themeRootDir, MODULES_DIRECTORY_NAME);
163
+ const localModulesPath = join(executionContext.themeRootDir, 'modules');
156
164
  const fetchedThemePath = join(tmpDir, name);
157
- const fetchedModulesPath = join(fetchedThemePath, MODULES_DIRECTORY_NAME);
165
+ const fetchedModulesPath = join(fetchedThemePath, 'modules');
158
166
  if ((await directoryExists(localModulesPath)) && (await directoryExists(fetchedModulesPath)))
159
- await ThemeResourcesWithIdDirectoryUtils.updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localModulesPath, fetchedModulesPath, fetchedThemePath);
167
+ await ThemeResourcesWithIdDirectoryUtils.updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localModulesPath, fetchedModulesPath, fetchedThemePath, loggerApi);
160
168
  this.#spinner.stop();
161
169
  const changes = await themeMergeApi.getChangesBetweenThemes(fetchedThemePath, executionContext.themeRootDir);
162
- const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
170
+ const themeChecksums = new ThemeChecksums({
171
+ themeDir: executionContext.themeRootDir,
172
+ loggerApi
173
+ });
163
174
  if (changes.length && (await themeChecksums.hasThemeBeenModified())) {
164
175
  renderOnce(React.createElement(ThemePullUnpublishedChangesWarning, { changes: changes }));
165
176
  const { proceed } = await promptConfirmation('Do you want to continue and overwrite local changes?');
@@ -4,6 +4,8 @@ import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../cli/fea
4
4
  import { THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../../features/theme/actions/theme_actions_constants.js';
5
5
  import { THEME_PUSH_API_NAME } from '../../features/theme/push/theme_push_constants.js';
6
6
  import { ThemeMetaDataUtils } from '../../features/theme/utils/meta_data/theme_meta_data_utils.js';
7
+ import { mapChecksumToTree } from '../../../utils/checksums/checksums_utils.js';
8
+ import { mapToPermissionsTree } from '../../utils/directory_validator/directory_validator_utils.js';
7
9
  import { renderOnce } from '../../../ui/ui_utils.js';
8
10
  import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
9
11
  import React from 'react';
@@ -12,7 +14,7 @@ import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_c
12
14
  import { ThemePushedSuccess } from './ui/theme_pushed_success.js';
13
15
  import ora from 'ora';
14
16
  import { ThemePushSkipInfo } from './ui/theme_push_skip_into.js';
15
- import { ThemeFilesUtils } from '../../features/theme/utils/files/theme_files_utils.js';
17
+ import { ThemeFilesStructureUtils } from '../../features/theme/utils/files_structure/theme_files_structure_utils.js';
16
18
  import { ThemeInfoUtils } from '../../features/theme/info/theme_info_utils.js';
17
19
  import { ThemeChecksums } from '../../class/checksums/theme_checksums.js';
18
20
  import { ThemeFilesUpload } from '../../class/files_upload/theme_files_upload.js';
@@ -22,10 +24,8 @@ import { MissingThemeFiles } from '../ui/missing_theme_files.js';
22
24
  import { SHOPER_THEME_METADATA_DIR } from '../../constants/directory_contstants.js';
23
25
  import { THEME_FILES_STRUCTURE_FILE_NAME } from '../../features/theme/theme_constants.js';
24
26
  import { ThemeError } from '../ui/theme_error.js';
25
- import { mapToPermissionsTree } from '../../utils/directory_validator/directory_validator_utils.js';
26
- import { mapChecksumToTree } from '../../../utils/checksums/checksums_utils.js';
27
27
  import { ThemeUnpermittedActionsError } from './ui/theme_unpermitted_actions_error.js';
28
- import { promptConfirmation } from '../../../ui/prompts/prompt_confirmation.js';
28
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
29
29
  export class ThemePushCommand extends BaseThemeCommand {
30
30
  static summary = 'Uploads your local theme files to the store and overwrites the current version of the theme in your store.';
31
31
  static description = 'Check your local changes before pushing.\n\nYou must run this command from a specific theme directory (ID not needed).';
@@ -37,6 +37,7 @@ export class ThemePushCommand extends BaseThemeCommand {
37
37
  ];
38
38
  async run() {
39
39
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
40
+ const loggerApi = this.getApi(LOGGER_API_NAME);
40
41
  const themePushApi = this.getApi(THEME_PUSH_API_NAME);
41
42
  const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
42
43
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
@@ -52,7 +53,10 @@ export class ThemePushCommand extends BaseThemeCommand {
52
53
  }
53
54
  let spinner;
54
55
  try {
55
- const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
56
+ const themeChecksums = new ThemeChecksums({
57
+ themeDir: executionContext.themeRootDir,
58
+ loggerApi
59
+ });
56
60
  await ThemeMetaDataUtils.ensureThemeWorkUrlMatch(executionContext.themeRootDir, credentials.shopUrl);
57
61
  const pushAction = themeActionsApi.getThemeAction({
58
62
  actionType: THEME_ACTIONS_TYPES.push,
@@ -64,7 +68,7 @@ export class ThemePushCommand extends BaseThemeCommand {
64
68
  return;
65
69
  }
66
70
  const initialChecksums = await themeChecksums.getInitialChecksums();
67
- const permissions = await ThemeFilesUtils.getFilesPermissions(executionContext.themeRootDir);
71
+ const permissions = await ThemeFilesStructureUtils.getFilesPermissions(executionContext.themeRootDir);
68
72
  const themeFilesUploadApi = new ThemeFilesUpload({
69
73
  themeRootDir: executionContext.themeRootDir,
70
74
  credentials,
@@ -76,7 +80,7 @@ export class ThemePushCommand extends BaseThemeCommand {
76
80
  renderOnce(React.createElement(ThemePushSkipInfo, null));
77
81
  return;
78
82
  }
79
- const validationResult = await ThemeFilesUtils.validateThemeDirectoryStructure({
83
+ const validationResult = await ThemeFilesStructureUtils.validateThemeDirectoryStructure({
80
84
  //TDO przeniesc do theme checksums
81
85
  checksums: mapChecksumToTree(initialChecksums),
82
86
  permissions: mapToPermissionsTree(permissions),
@@ -88,36 +92,26 @@ export class ThemePushCommand extends BaseThemeCommand {
88
92
  renderOnce(React.createElement(ThemeUnpermittedActionsError, { unpermittedActions: validationResult.unpermittedActions }));
89
93
  return;
90
94
  }
91
- const filesStructure = await ThemeFilesUtils.getThemeFilesStructure(executionContext.themeRootDir);
95
+ const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(executionContext.themeRootDir);
92
96
  if (!filesStructure) {
93
97
  renderOnce(React.createElement(MissingThemeFiles, { files: `${SHOPER_THEME_METADATA_DIR}/${THEME_FILES_STRUCTURE_FILE_NAME}` }));
94
98
  return;
95
99
  }
96
100
  spinner = ora('Pushing theme...').start();
97
- const partialPushAction = themeActionsApi.getThemeAction({
98
- actionType: THEME_ACTIONS_TYPES.partialPush,
99
- themeId: executionContext.themeId,
100
- credentials
101
- });
102
- if (!pushAction) {
103
- renderOnce(React.createElement(UnpermittedCommandError, { themeId: executionContext.themeId, commandName: "push" }));
104
- return;
105
- }
106
- await themePushApi.partialPush({
101
+ await themePushApi.push({
107
102
  credentials,
108
103
  filesStructure,
109
- action: partialPushAction,
104
+ pushAction,
110
105
  themeChecksums,
111
106
  executionContext,
112
107
  themeFilesUploadApi
113
108
  });
114
109
  spinner.stop();
115
- await promptConfirmation('press any key to continue...');
116
110
  renderOnce(React.createElement(ThemePushedSuccess, { themeName: await ThemeInfoUtils.getThemeName(executionContext.themeRootDir) }));
117
111
  }
118
112
  catch (err) {
119
113
  spinner?.stop();
120
- await promptConfirmation('press any key to continue...');
114
+ loggerApi.error('Error during theme push', { error: err });
121
115
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
122
116
  }
123
117
  }
@@ -1,6 +1,7 @@
1
1
  import { BaseThemeCommand } from '../class/base_theme_command.js';
2
2
  import { CLI_AUTH_API_NAME } from '../../cli/auth/cli_auth_constants.js';
3
3
  import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../cli/features/execution_context/execution_context_constants.js';
4
+ import { ThemeFilesStructureUtils } from '../features/theme/utils/files_structure/theme_files_structure_utils.js';
4
5
  import { ThemeChecksums } from '../class/checksums/theme_checksums.js';
5
6
  import { THEME_VERIFY_API_NAME } from '../features/theme/verify/theme_verify_constants.js';
6
7
  import { THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../features/theme/actions/theme_actions_constants.js';
@@ -17,13 +18,14 @@ import { MissingCredentialsError } from '../../cli/commands/auth/ui/missing_cred
17
18
  import { OutsideOfThemeDirectoryContextError } from './ui/ouside_of_theme_directory_context_error.js';
18
19
  import ora from 'ora';
19
20
  import { ThemeError } from './ui/theme_error.js';
20
- import { ThemeFilesUtils } from '../features/theme/utils/files/theme_files_utils.js';
21
+ import { LOGGER_API_NAME } from '../../cli/utilities/features/logger/logger_constants.js';
21
22
  export class ThemeVerifyCommand extends BaseThemeCommand {
22
23
  static description = 'Verify theme files structure';
23
24
  async run() {
24
25
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
25
26
  const credentials = cliAuthApi.getCredentials();
26
27
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
28
+ const loggerApi = this.getApi(LOGGER_API_NAME);
27
29
  if (!credentials) {
28
30
  renderOnce(React.createElement(MissingCredentialsError, null));
29
31
  return;
@@ -33,8 +35,11 @@ export class ThemeVerifyCommand extends BaseThemeCommand {
33
35
  renderOnce(React.createElement(OutsideOfThemeDirectoryContextError, null));
34
36
  return;
35
37
  }
36
- const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
37
- const permissions = await ThemeFilesUtils.getFilesPermissions(executionContext.themeRootDir);
38
+ const themeChecksums = new ThemeChecksums({
39
+ themeDir: executionContext.themeRootDir,
40
+ loggerApi
41
+ });
42
+ const permissions = await ThemeFilesStructureUtils.getFilesPermissions(executionContext.themeRootDir);
38
43
  if (!themeChecksums || !permissions)
39
44
  this.error('Theme checksums or permissions not found. Please ensure you are in the correct theme directory.');
40
45
  let spinner;
@@ -51,7 +56,7 @@ export class ThemeVerifyCommand extends BaseThemeCommand {
51
56
  themeId: executionContext.themeId,
52
57
  credentials
53
58
  });
54
- const filesStructure = await ThemeFilesUtils.getThemeFilesStructure(executionContext.themeRootDir);
59
+ const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(executionContext.themeRootDir);
55
60
  if (!filesStructure) {
56
61
  renderOnce(React.createElement(MissingThemeFiles, { files: `${SHOPER_THEME_METADATA_DIR}/${THEME_FILES_STRUCTURE_FILE_NAME}` }));
57
62
  return;
@@ -9,7 +9,7 @@ import React from 'react';
9
9
  import { ThemeWorkUrlMismatch } from './theme_work_url_mismatch.js';
10
10
  import { EXECUTION_CONTEXTS } from '../../../cli/features/execution_context/execution_context_constants.js';
11
11
  export const ThemeError = ({ err, executionContext }) => {
12
- if (err?.code === THEME_ACTION_NOT_FOUND_ERROR_CODE && executionContext.type === EXECUTION_CONTEXTS.theme) {
12
+ if (err?.code === THEME_ACTION_NOT_FOUND_ERROR_CODE && executionContext?.type === EXECUTION_CONTEXTS.theme) {
13
13
  return (React.createElement(UnpermittedCommandError, { themeId: executionContext.themeId, commandName: "verify" }));
14
14
  }
15
15
  if (err?.code === THEME_ARCHIVE_UPLOAD_ERROR) {
@@ -19,8 +19,8 @@ export const ThemeError = ({ err, executionContext }) => {
19
19
  return React.createElement(ThemeWorkUrlMismatch, { command: "verify" });
20
20
  }
21
21
  if (err?.code === THEME_FILES_UPLOAD_ERROR) {
22
- return (React.createElement(Error, { header: "Uploading theme files to the shop failed." },
23
- React.createElement(Text, null, "Please ensure that the files are not corrupted and that the file extensions are supported or file size is not too large.")));
22
+ return (React.createElement(Error, { header: "Uploading theme files to the shop failed.\n" },
23
+ React.createElement(Text, null, "The rejected files have been removed locally. Please ensure that the files are not corrupted and that the file extensions are supported.")));
24
24
  }
25
25
  if (err?.message) {
26
26
  return React.createElement(ValidationErrors, { errors: err.message });
@@ -1,17 +1,26 @@
1
1
  import { STORE_THEMES_ACTIONS_TTL } from './theme_actions_service_constants.js';
2
- import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
2
+ import { AppError } from '../../../../../cli/utilities/features/logger/logs/app_error.js';
3
3
  import { getNMinutesFromNow } from '../../../../../utils/date_utils.js';
4
4
  import { computeChecksum } from '../../../../../utils/checksums/checksums_utils.js';
5
5
  import { THEME_ACTION_NOT_FOUND_ERROR_CODE, THEME_ACTION_NOTS_FOUND_ERROR_CODE } from '../theme_actions_constants.js';
6
6
  export class ThemeActionsService {
7
7
  #themesListApi;
8
8
  #themesActionsStore;
9
- constructor({ themesListApi, themesActionsStore }) {
9
+ #loggerApi;
10
+ constructor({ themesListApi, themesActionsStore, loggerApi }) {
10
11
  this.#themesListApi = themesListApi;
11
12
  this.#themesActionsStore = themesActionsStore;
13
+ this.#loggerApi = loggerApi;
12
14
  }
13
15
  getThemeAction({ actionType, themeId, credentials }) {
14
16
  const storeActions = this.#themesActionsStore.get(this._getKey(credentials.shopUrl));
17
+ this.#loggerApi.debug('Retrieving theme action', {
18
+ details: {
19
+ actionType,
20
+ themeId,
21
+ shopUrl: credentials.shopUrl
22
+ }
23
+ });
15
24
  if (!storeActions)
16
25
  throw new AppError({
17
26
  code: THEME_ACTION_NOTS_FOUND_ERROR_CODE,
@@ -27,6 +36,12 @@ export class ThemeActionsService {
27
36
  }
28
37
  removeThemeActions({ themeId, credentials }) {
29
38
  const storeActions = this.#themesActionsStore.get(this._getKey(credentials.shopUrl));
39
+ this.#loggerApi.debug('Removing theme actions', {
40
+ details: {
41
+ themeId,
42
+ shopUrl: credentials.shopUrl
43
+ }
44
+ });
30
45
  if (!storeActions || !storeActions.actions[themeId]) {
31
46
  throw new AppError({
32
47
  code: THEME_ACTION_NOTS_FOUND_ERROR_CODE,
@@ -40,10 +55,17 @@ export class ThemeActionsService {
40
55
  if (!themeId)
41
56
  return;
42
57
  const actionsData = this.#themesActionsStore.get(this._getKey(credentials.shopUrl));
58
+ this.#loggerApi.info('Ensuring theme actions are up to date', {
59
+ details: {
60
+ themeId,
61
+ shopUrl: credentials.shopUrl
62
+ }
63
+ });
43
64
  if (actionsData &&
44
65
  this._isValidThemesActions(actionsData) &&
45
66
  actionsData.actions[themeId] &&
46
67
  !this._hasThemesActionsExpired(this._getKey(credentials.shopUrl))) {
68
+ this.#loggerApi.debug('Theme actions are valid and not expired. Skipping fetch.');
47
69
  return Promise.resolve();
48
70
  }
49
71
  this._cleanExpiredActions();
@@ -52,6 +74,7 @@ export class ThemeActionsService {
52
74
  actions,
53
75
  expires: getNMinutesFromNow(STORE_THEMES_ACTIONS_TTL)
54
76
  });
77
+ this.#loggerApi.info('Fetched and stored new theme actions.');
55
78
  }
56
79
  _hasThemesActionsExpired(key) {
57
80
  const expires = this.#themesActionsStore.get(key)?.expires;
@@ -64,6 +87,11 @@ export class ThemeActionsService {
64
87
  return true;
65
88
  }
66
89
  async _fetchStoreThemesActions(credentials) {
90
+ this.#loggerApi.info('Fetching themes actions for store', {
91
+ details: {
92
+ shopUrl: credentials.shopUrl
93
+ }
94
+ });
67
95
  const themes = await this.#themesListApi.getThemes(credentials);
68
96
  if (!Array.isArray(themes))
69
97
  throw new AppError({
@@ -87,6 +115,11 @@ export class ThemeActionsService {
87
115
  }
88
116
  clearThemesActions({ credentials }) {
89
117
  const key = this._getKey(credentials.shopUrl);
118
+ this.#loggerApi.debug('Clearing themes actions for store', {
119
+ details: {
120
+ shopUrl: credentials.shopUrl
121
+ }
122
+ });
90
123
  this.#themesActionsStore.remove(key);
91
124
  }
92
125
  _getKey(shopUrl) {
@@ -94,14 +127,21 @@ export class ThemeActionsService {
94
127
  }
95
128
  _cleanExpiredActions() {
96
129
  const keys = this.#themesActionsStore.getKeys();
130
+ this.#loggerApi.debug('Cleaning expired actions');
97
131
  keys.forEach((key) => {
98
132
  const actionsData = this.#themesActionsStore.get(key);
99
133
  if (!actionsData || this._hasThemesActionsExpired(key)) {
134
+ this.#loggerApi.debug('Cleaning expired action', {
135
+ details: {
136
+ key
137
+ }
138
+ });
100
139
  this.#themesActionsStore.remove(key);
101
140
  }
102
141
  });
103
142
  }
104
143
  clearAllActions() {
144
+ this.#loggerApi.debug('Clearing all actions');
105
145
  this.#themesActionsStore.clear();
106
146
  }
107
147
  }
@@ -8,8 +8,7 @@ export const THEME_ACTIONS_TYPES = {
8
8
  delete: 'delete',
9
9
  publishForm: 'publish_form',
10
10
  publish: 'publish',
11
- verify: 'verify',
12
- partialPush: 'partial_push'
11
+ verify: 'verify'
13
12
  };
14
13
  export const THEME_ACTION_DATA_TYPE = {
15
14
  file: 'file',
@@ -5,10 +5,12 @@ import { CLI_DATA_DIRECTORY_API_NAME } from '../../../../cli/features/data_direc
5
5
  import { THEME_ACTIONS_FEATURE_NAME, THEMES_ACTIONS_FILE_NAME } from './theme_actions_constants.js';
6
6
  import { ThemeActionsApi } from './api/theme_actions_api.js';
7
7
  import { ThemeActionsService } from './service/theme_actions_service.js';
8
+ import { LOGGER_API_NAME } from '../../../../cli/utilities/features/logger/logger_constants.js';
8
9
  export class ThemeActionsInitializer extends AsyncFeatureInitializer {
9
10
  static featureName = THEME_ACTIONS_FEATURE_NAME;
10
11
  async init() {
11
12
  const themesListApi = this.getApiSync(THEMES_LIST_API_NAME);
13
+ const loggerApi = this.getApiSync(LOGGER_API_NAME);
12
14
  const cliDataDirectoryApi = this.getApiSync(CLI_DATA_DIRECTORY_API_NAME);
13
15
  const themesActionsStore = new JsonCache({
14
16
  path: cliDataDirectoryApi.getDataDirectoryFullPath(),
@@ -19,7 +21,7 @@ export class ThemeActionsInitializer extends AsyncFeatureInitializer {
19
21
  cores: [
20
22
  {
21
23
  type: FEATURE_CORES_TYPES.api,
22
- instance: new ThemeActionsApi(new ThemeActionsService({ themesListApi, themesActionsStore }))
24
+ instance: new ThemeActionsApi(new ThemeActionsService({ themesListApi, themesActionsStore, loggerApi }))
23
25
  }
24
26
  ]
25
27
  };
@@ -3,10 +3,8 @@ import { basename, looksLikeDirectory, toUnixPath } from '../../../../utils/path
3
3
  import { THEME_ACTION_DATA_TYPE } from './theme_actions_constants.js';
4
4
  import globs from 'fast-glob';
5
5
  import { THEME_PUSH_WILDCARD_GLOBS_FOR_FILES } from '../push/service/theme_push_service_constants.js';
6
- import micromatch from 'micromatch';
7
- import difference from 'lodash/difference.js';
8
6
  export class ThemeActionsUtils {
9
- static getFilesGlobsThatMatchesAction({ filesStructure, actionValue, actionType }) {
7
+ static getFilesGlobsThatMatchesActionName({ filesStructure, actionValue, actionType }) {
10
8
  return Object.entries(filesStructure).reduce((acc, [filePath, fileStructureItem]) => {
11
9
  if (fileStructureItem._links?.[actionType] && this._doesActionValueMatch(fileStructureItem._links[actionType], actionValue)) {
12
10
  return [...acc, toUnixPath(filePath)];
@@ -14,32 +12,11 @@ export class ThemeActionsUtils {
14
12
  return acc;
15
13
  }, []);
16
14
  }
17
- static async getFilesThatMatchesAction({ actionType, actionValue, filesStructure, rootDir }) {
18
- return await globs(ThemeActionsUtils.getFilesGlobsThatMatchesAction({
19
- actionType,
20
- actionValue,
21
- filesStructure
22
- }), {
23
- suppressErrors: true,
24
- onlyFiles: true,
25
- cwd: rootDir
26
- });
27
- }
28
- static async getDeletedFilesThatMatchesAction({ actionType, actionValue, themeChecksums, filesStructure }) {
29
- const deletedFiles = await themeChecksums.getDeletedFiles();
30
- const globs = ThemeActionsUtils.getFilesGlobsThatMatchesAction({
31
- actionType,
32
- actionValue,
33
- filesStructure
34
- });
35
- return deletedFiles.filter((path) => !looksLikeDirectory(path) && micromatch.isMatch(path, globs));
36
- }
37
- static async getFilesRecordsFromActionData({ themeRootDir, themeAction, filesStructure, themeChecksums }) {
15
+ static async getFilesRecordsFromActionData({ themeRootDir, themeAction, filesStructure }) {
38
16
  const filesRecords = [];
39
- const initialChecksums = await themeChecksums.getInitialChecksums();
40
17
  for (const [actionKey, actionData] of Object.entries(themeAction.data)) {
41
18
  if (actionData.type === THEME_ACTION_DATA_TYPE.file) {
42
- const filesGlobs = ThemeActionsUtils.getFilesGlobsThatMatchesAction({
19
+ const filesGlobs = ThemeActionsUtils.getFilesGlobsThatMatchesActionName({
43
20
  //TODO remove when backend fixed
44
21
  actionType: 'push',
45
22
  // actionType: themeAction.actionType,
@@ -47,7 +24,6 @@ export class ThemeActionsUtils {
47
24
  filesStructure
48
25
  });
49
26
  for (const fileGlob of filesGlobs) {
50
- const checksumMatchedFiles = micromatch(Object.keys(initialChecksums), [fileGlob]);
51
27
  const files = await globs(fileGlob, {
52
28
  suppressErrors: true,
53
29
  onlyFiles: true,
@@ -59,15 +35,13 @@ export class ThemeActionsUtils {
59
35
  ? fileGlob.slice(0, fileGlob.length - 2)
60
36
  : fileGlob;
61
37
  }
62
- const deletedFiles = difference(checksumMatchedFiles, files);
63
- for (const filePath of [...files, ...deletedFiles]) {
38
+ for (const filePath of files) {
64
39
  filesRecords.push({
65
40
  actionData,
66
41
  actionKey,
67
42
  path: filePath,
68
43
  fileName: basename(filePath),
69
- fileGlob: processedFileGlob,
70
- state: await themeChecksums.getFileState(filePath)
44
+ fileGlob: processedFileGlob
71
45
  });
72
46
  }
73
47
  }