@shoper/cli 0.5.2 → 0.6.1

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 (94) hide show
  1. package/.docs/images/shoper-for-developers.svg +1 -0
  2. package/README.md +4 -2
  3. package/build/cli/auth/cli_auth_errors_factory.js +1 -1
  4. package/build/cli/auth/cli_auth_initializer.js +6 -1
  5. package/build/cli/auth/service/cli_auth_service.js +11 -2
  6. package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +1 -1
  7. package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +6 -1
  8. package/build/cli/auth/tokens/service/cli_auth_tokens_service.js +8 -1
  9. package/build/cli/class/base_command.js +15 -1
  10. package/build/cli/class/cli_help.js +24 -0
  11. package/build/cli/class/errors/file_system_errors_factory.js +3 -3
  12. package/build/cli/class/errors/http/http_errors_factory.js +1 -1
  13. package/build/cli/commands/auth/cli_auth_add_token_command.js +5 -0
  14. package/build/cli/commands/auth/cli_auth_list_tokens_command.js +20 -11
  15. package/build/cli/commands/auth/cli_auth_logout_command.js +5 -0
  16. package/build/cli/commands/auth/cli_auth_remove_token_command.js +5 -0
  17. package/build/cli/commands/auth/cli_auth_switch_token_command.js +8 -0
  18. package/build/cli/commands/cli_update_command.js +5 -0
  19. package/build/cli/core/cli_setup.js +5 -13
  20. package/build/cli/features/execution_context/execution_context_service.js +2 -0
  21. package/build/cli/features/version/service/cli_version_service.js +2 -2
  22. package/build/cli/hooks/authorization/ensure_authorization_hook.js +9 -2
  23. package/build/cli/hooks/ensure_cli_initialized_hook.js +1 -6
  24. package/build/cli/hooks/ensure_logs_flushed_hook.js +7 -0
  25. package/build/cli/{features → utilities/features}/http_requester/http_client.js +2 -2
  26. package/build/cli/{features → utilities/features}/http_requester/http_requester_initializer.js +1 -1
  27. package/build/cli/utilities/features/logger/api/logger_api.js +28 -0
  28. package/build/cli/utilities/features/logger/logger_constants.js +7 -0
  29. package/build/cli/utilities/features/logger/logger_initializer.js +44 -0
  30. package/build/cli/utilities/features/logger/logs/app_error.js +14 -0
  31. package/build/cli/utilities/features/logger/logs/app_log.js +40 -0
  32. package/build/cli/{class/errors/app/app_error_constants.js → utilities/features/logger/logs/app_logs_constants.js} +1 -1
  33. package/build/cli/utilities/features/logger/service/logger_service.js +108 -0
  34. package/build/cli/utilities/features/logger/transports/log_object_map_transport.js +15 -0
  35. package/build/index.js +14 -2
  36. package/build/theme/class/archive/theme_archive.js +2 -1
  37. package/build/theme/class/archive/theme_archive_errors_factory.js +2 -2
  38. package/build/theme/class/checksums/theme_checksums.js +25 -5
  39. package/build/theme/class/checksums/theme_checksums_error_factory.js +3 -3
  40. package/build/theme/class/fetch_resources/fetch_resources.js +34 -4
  41. package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +1 -1
  42. package/build/theme/commands/delete/theme_delete_command.js +3 -2
  43. package/build/theme/commands/info/theme_info_command.js +3 -0
  44. package/build/theme/commands/init/theme_init_command.js +10 -1
  45. package/build/theme/commands/list/theme_list_command.js +22 -8
  46. package/build/theme/commands/publish/theme_publish_command.js +5 -1
  47. package/build/theme/commands/pull/theme_pull_command.js +17 -5
  48. package/build/theme/commands/push/theme_push_command.js +7 -1
  49. package/build/theme/commands/theme_verify_command.js +6 -1
  50. package/build/theme/commands/ui/theme_error.js +1 -1
  51. package/build/theme/features/theme/actions/service/theme_actions_service.js +42 -2
  52. package/build/theme/features/theme/actions/theme_actions_initializer.js +3 -1
  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 +35 -6
  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 +32 -6
  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 +38 -4
  60. package/build/theme/features/theme/merge/theme_merge_initializer.js +3 -1
  61. package/build/theme/features/theme/push/service/theme_push_service.js +38 -10
  62. package/build/theme/features/theme/push/theme_push_errors_factory.js +2 -2
  63. package/build/theme/features/theme/push/theme_push_initializer.js +3 -1
  64. package/build/theme/features/theme/push/theme_push_utils.js +1 -1
  65. package/build/theme/features/theme/utils/files_structure/theme_file_structure_errors_factory.js +2 -3
  66. package/build/theme/features/theme/utils/hidden_directory/hidden_directory_utils.js +5 -2
  67. package/build/theme/features/theme/utils/meta_data/theme_meta_data_error_factory.js +1 -1
  68. package/build/theme/features/theme/utils/resources/theme_resources_with_id_directory_utils.js +5 -2
  69. package/build/theme/features/theme/verify/theme_verify_initializer.js +4 -3
  70. package/build/theme/features/theme/verify/verify/theme_verify_service.js +20 -2
  71. package/build/theme/features/theme/watch/api/theme_watch_api.js +11 -0
  72. package/build/theme/features/theme/watch/service/theme_watch_service.js +48 -0
  73. package/build/theme/features/theme/watch/theme_watch_constants.js +2 -0
  74. package/build/theme/features/theme/watch/theme_watch_initializer.js +20 -0
  75. package/build/theme/features/themes/list/services/themes_list_service.js +36 -5
  76. package/build/theme/features/themes/list/themes_list_initializer.js +3 -1
  77. package/build/theme/hooks/ensure_theme_meta_data_untouched_hook.js +4 -2
  78. package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_hook.js +7 -2
  79. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +2 -3
  80. package/build/ui/gradient.js +2 -0
  81. package/build/ui/hooks/stream_hook.js +26 -0
  82. package/build/utils/download_file/download_file_errors_factory.js +1 -1
  83. package/build/utils/download_file/download_file_utils.js +19 -1
  84. package/build/utils/fs/errors/stream_read_error.js +7 -5
  85. package/build/utils/fs/errors/stream_write_error.js +7 -5
  86. package/build/utils/get_api.js +9 -0
  87. package/build/utils/use_api.js +5 -0
  88. package/build/utils/zip/create_zip_utils.js +21 -9
  89. package/build/utils/zip/errors/create_zip_error.js +7 -5
  90. package/build/utils/zip/errors/open_zip_error.js +7 -5
  91. package/build/utils/zip/extract_zip_utils.js +90 -15
  92. package/oclif.config.js +3 -1
  93. package/package.json +15 -5
  94. package/build/cli/class/errors/app/app_error.js +0 -17
@@ -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
  }
@@ -24,7 +24,8 @@ import { Info } from '../../../ui/message_box/info.js';
24
24
  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
- import { ThemeError } from '../ui/theme_error.js'; //TODO jak jest error w pullu wowczas usuwamy docelowo pociagniety skin
27
+ import { ThemeError } from '../ui/theme_error.js';
28
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
28
29
  //TODO jak jest error w pullu wowczas usuwamy docelowo pociagniety skin
29
30
  export class ThemePullCommand extends BaseThemeCommand {
30
31
  static summary = 'Downloads the current version of your theme from the store and overwrites your local theme files.';
@@ -60,6 +61,7 @@ export class ThemePullCommand extends BaseThemeCommand {
60
61
  const themeFetchApi = this.getApi(THEME_FETCH_API_NAME);
61
62
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
62
63
  const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
64
+ const loggerApi = this.getApi(LOGGER_API_NAME);
63
65
  const credentials = cliAuthApi.getCredentials();
64
66
  if (!credentials) {
65
67
  renderOnce(React.createElement(MissingCredentialsError, null));
@@ -85,12 +87,19 @@ export class ThemePullCommand extends BaseThemeCommand {
85
87
  themeActionsApi,
86
88
  fetchType: this.flags.type,
87
89
  executionContext,
88
- credentials
90
+ credentials,
91
+ loggerApi
89
92
  });
90
93
  }
91
94
  }
92
95
  catch (err) {
93
96
  this.#spinner?.stop();
97
+ loggerApi.error('Error occurred during theme pull operation', {
98
+ error: err,
99
+ details: {
100
+ executionContext
101
+ }
102
+ });
94
103
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
95
104
  }
96
105
  }
@@ -124,7 +133,7 @@ export class ThemePullCommand extends BaseThemeCommand {
124
133
  this.#spinner.stop();
125
134
  renderOnce(React.createElement(ThemePulledSuccess, null));
126
135
  }
127
- async _pullThemeIntoExistingOne({ themeId, themeFetchApi, themeActionsApi, fetchType, executionContext, credentials }) {
136
+ async _pullThemeIntoExistingOne({ themeId, themeFetchApi, themeActionsApi, fetchType, executionContext, credentials, loggerApi }) {
128
137
  //TODO move these logi somvewhere else?
129
138
  await ThemeMetaDataUtils.ensureThemeWorkUrlMatch(executionContext.themeRootDir, credentials.shopUrl);
130
139
  const pullAction = themeActionsApi.getThemeAction({
@@ -155,10 +164,13 @@ export class ThemePullCommand extends BaseThemeCommand {
155
164
  const fetchedThemePath = join(tmpDir, name);
156
165
  const fetchedModulesPath = join(fetchedThemePath, 'modules');
157
166
  if ((await directoryExists(localModulesPath)) && (await directoryExists(fetchedModulesPath)))
158
- await ThemeResourcesWithIdDirectoryUtils.updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localModulesPath, fetchedModulesPath, fetchedThemePath);
167
+ await ThemeResourcesWithIdDirectoryUtils.updateDirectoryNamesOfResourcesWithIdAccordingToLocalThemeNames(localModulesPath, fetchedModulesPath, fetchedThemePath, loggerApi);
159
168
  this.#spinner.stop();
160
169
  const changes = await themeMergeApi.getChangesBetweenThemes(fetchedThemePath, executionContext.themeRootDir);
161
- const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
170
+ const themeChecksums = new ThemeChecksums({
171
+ themeDir: executionContext.themeRootDir,
172
+ loggerApi
173
+ });
162
174
  if (changes.length && (await themeChecksums.hasThemeBeenModified())) {
163
175
  renderOnce(React.createElement(ThemePullUnpublishedChangesWarning, { changes: changes }));
164
176
  const { proceed } = await promptConfirmation('Do you want to continue and overwrite local changes?');
@@ -25,6 +25,7 @@ import { SHOPER_THEME_METADATA_DIR } from '../../constants/directory_contstants.
25
25
  import { THEME_FILES_STRUCTURE_FILE_NAME } from '../../features/theme/theme_constants.js';
26
26
  import { ThemeError } from '../ui/theme_error.js';
27
27
  import { ThemeUnpermittedActionsError } from './ui/theme_unpermitted_actions_error.js';
28
+ import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
28
29
  export class ThemePushCommand extends BaseThemeCommand {
29
30
  static summary = 'Uploads your local theme files to the store and overwrites the current version of the theme in your store.';
30
31
  static description = 'Check your local changes before pushing.\n\nYou must run this command from a specific theme directory (ID not needed).';
@@ -36,6 +37,7 @@ export class ThemePushCommand extends BaseThemeCommand {
36
37
  ];
37
38
  async run() {
38
39
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
40
+ const loggerApi = this.getApi(LOGGER_API_NAME);
39
41
  const themePushApi = this.getApi(THEME_PUSH_API_NAME);
40
42
  const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
41
43
  const executionContextApi = this.getApi(EXECUTION_CONTEXT_API_NAME);
@@ -51,7 +53,10 @@ export class ThemePushCommand extends BaseThemeCommand {
51
53
  }
52
54
  let spinner;
53
55
  try {
54
- const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
56
+ const themeChecksums = new ThemeChecksums({
57
+ themeDir: executionContext.themeRootDir,
58
+ loggerApi
59
+ });
55
60
  await ThemeMetaDataUtils.ensureThemeWorkUrlMatch(executionContext.themeRootDir, credentials.shopUrl);
56
61
  const pushAction = themeActionsApi.getThemeAction({
57
62
  actionType: THEME_ACTIONS_TYPES.push,
@@ -106,6 +111,7 @@ export class ThemePushCommand extends BaseThemeCommand {
106
111
  }
107
112
  catch (err) {
108
113
  spinner?.stop();
114
+ loggerApi.error('Error during theme push', { error: err });
109
115
  renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
110
116
  }
111
117
  }
@@ -18,12 +18,14 @@ import { MissingCredentialsError } from '../../cli/commands/auth/ui/missing_cred
18
18
  import { OutsideOfThemeDirectoryContextError } from './ui/ouside_of_theme_directory_context_error.js';
19
19
  import ora from 'ora';
20
20
  import { ThemeError } from './ui/theme_error.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,7 +35,10 @@ export class ThemeVerifyCommand extends BaseThemeCommand {
33
35
  renderOnce(React.createElement(OutsideOfThemeDirectoryContextError, null));
34
36
  return;
35
37
  }
36
- const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
38
+ const themeChecksums = new ThemeChecksums({
39
+ themeDir: executionContext.themeRootDir,
40
+ loggerApi
41
+ });
37
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.');
@@ -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) {
@@ -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
  }
@@ -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,18 +3,29 @@ import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/do
3
3
  import { STATUS_CODES } from '@dreamcommerce/star_core';
4
4
  export class ThemeDeleteService {
5
5
  #httpApi;
6
- constructor(httpApi) {
6
+ #logger;
7
+ constructor({ logger, httpApi }) {
7
8
  this.#httpApi = httpApi;
9
+ this.#logger = logger;
8
10
  }
9
11
  async deleteTheme({ actionData, credentials }) {
10
12
  try {
13
+ this.#logger.info('Deleting theme', {
14
+ details: {
15
+ actionData
16
+ }
17
+ });
11
18
  const { response: request } = this.#httpApi.deleteTheme({ actionData, shopUrl: credentials.shopUrl });
12
19
  const response = await request;
13
20
  if (response?.status !== STATUS_CODES.ok)
14
21
  return;
22
+ this.#logger.info('Successfully deleted theme');
15
23
  return response?.data;
16
24
  }
17
25
  catch (err) {
26
+ this.#logger.error('Error deleting theme', {
27
+ error: err
28
+ });
18
29
  //TODO to basic class
19
30
  switch (err.response?.status) {
20
31
  case 403:
@@ -3,11 +3,16 @@ import { ThemeDeleteApi } from './api/theme_delete_api.js';
3
3
  import { ThemeDeleteService } from './service/theme_delete_service.js';
4
4
  import { ThemeDeleteHttpApi } from './http/theme_delete_http_api.js';
5
5
  import { THEME_DELETE_FEATURE_NAME } from './theme_delete_constants.js';
6
+ import { LOGGER_API_NAME } from '../../../../cli/utilities/features/logger/logger_constants.js';
6
7
  export class ThemeDeleteInitializer extends SyncFeatureInitializer {
7
8
  static featureName = THEME_DELETE_FEATURE_NAME;
8
9
  init() {
9
10
  const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
10
- const service = new ThemeDeleteService(new ThemeDeleteHttpApi(httpApi));
11
+ const loggerApi = this.getApiSync(LOGGER_API_NAME);
12
+ const service = new ThemeDeleteService({
13
+ httpApi: new ThemeDeleteHttpApi(httpApi),
14
+ logger: loggerApi
15
+ });
11
16
  return {
12
17
  cores: [
13
18
  {
@@ -7,61 +7,90 @@ import { getResources, mapResourcesToTree, removeOldResources } from '../../../.
7
7
  import { FetchResources } from '../../../../class/fetch_resources/fetch_resources.js';
8
8
  import { jsonIndentTransform } from '../../../../../utils/stream_transforms/json_indent_transform.js';
9
9
  import { JSON_FILE_INDENT } from '../../../../../cli/cli_constants.js';
10
- import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
10
+ import { AppError } from '../../../../../cli/utilities/features/logger/logs/app_error.js';
11
11
  import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
12
12
  import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
13
13
  import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
14
14
  export class ThemeFetchService {
15
15
  #themeHttpApi;
16
16
  #httpApi;
17
- constructor({ themeHttpApi, httpApi }) {
17
+ #loggerApi;
18
+ constructor({ themeHttpApi, httpApi, loggerApi }) {
18
19
  this.#themeHttpApi = themeHttpApi;
19
20
  this.#httpApi = httpApi;
21
+ this.#loggerApi = loggerApi;
20
22
  }
21
23
  async fetchTheme({ credentials, action, config }) {
22
24
  const { dist } = config;
23
25
  const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
24
26
  const fetchType = config?.fetchType ?? THEME_FETCH_TYPES.full;
27
+ this.#loggerApi.debug('Temporary directory created.', { details: { path: tmpDir } });
28
+ this.#loggerApi.info('Fetching theme', {
29
+ details: {
30
+ fetchType
31
+ }
32
+ });
25
33
  const { shopUrl } = credentials;
34
+ this.#loggerApi.info('Downloading theme archive.');
26
35
  //TODO think global mechanism to handle when user ctr+c during download
27
36
  const { basename, filename } = await downloadFile({
28
37
  dist: tmpDir,
38
+ logger: this.#loggerApi,
29
39
  request: this.#themeHttpApi.fetchTheme(shopUrl, action.data[fetchType]).response
30
40
  });
41
+ this.#loggerApi.info('Theme archive downloaded.');
31
42
  const themeDir = join(dist, basename);
43
+ this.#loggerApi.info('Extracting theme archive');
32
44
  await extractZip({
33
45
  source: join(tmpDir, filename),
34
46
  dist: themeDir,
47
+ logger: this.#loggerApi,
35
48
  getTransforms: (fileName) => (fileName.endsWith('.json') ? [jsonIndentTransform(JSON_FILE_INDENT)] : [])
36
49
  });
50
+ this.#loggerApi.info('Theme archive extracted');
37
51
  if (fetchType === THEME_FETCH_TYPES.full) {
52
+ this.#loggerApi.info('Fetching theme resources for full theme.');
38
53
  const resources = await getResources(themeDir);
39
54
  await this.fetchResources(shopUrl, themeDir, resources);
40
55
  }
41
56
  try {
57
+ this.#loggerApi.debug('Updating theme files structure.');
42
58
  await ThemeFilesStructureUtils.updateFilesStructure(themeDir);
43
59
  }
44
- catch (err) {
60
+ catch (error) {
45
61
  throw new AppError({
46
62
  message: `Failed to update files structure in theme directory: ${themeDir}`,
47
63
  code: 'theme_files_structure_update_error',
48
- stack: err.stack
64
+ error
49
65
  });
50
66
  }
67
+ this.#loggerApi.debug('Creating .gitignore file.');
51
68
  await ThemeMetaDataUtils.createGitIgnoreFile(themeDir);
69
+ this.#loggerApi.debug('Updating metadata file.');
52
70
  await ThemeMetaDataUtils.updateMetadataFileWithWorkUrl(themeDir, credentials.shopUrl);
71
+ this.#loggerApi.debug('Updating theme checksums');
53
72
  /**
54
73
  * moze to nie powinno lezec tutaj :?
55
74
  */
56
- await new ThemeChecksums(themeDir).updateAllChecksums();
75
+ await new ThemeChecksums({
76
+ themeDir,
77
+ loggerApi: this.#loggerApi
78
+ }).updateAllChecksums();
79
+ this.#loggerApi.info('Theme fetch completed successfully');
57
80
  return {
58
81
  name: basename
59
82
  };
60
83
  }
61
84
  async fetchResources(shopUrl, dist, resources) {
85
+ this.#loggerApi.debug('Removing old resources.');
62
86
  await removeOldResources(dist, resources);
87
+ this.#loggerApi.debug('Mapping resources to tree.');
63
88
  const resourcesTree = mapResourcesToTree(resources);
64
- await Promise.all(Object.keys(resourcesTree).map((resource) => new FetchResources(this.#httpApi).fetchResources({
89
+ this.#loggerApi.debug('Fetching resources from remote.');
90
+ await Promise.all(Object.keys(resourcesTree).map((resource) => new FetchResources({
91
+ httpApi: this.#httpApi,
92
+ loggerApi: this.#loggerApi
93
+ }).fetchResources({
65
94
  resourcesPart: resourcesTree[resource],
66
95
  dist,
67
96
  parts: [resource],
@@ -3,12 +3,15 @@ import { ThemeFetchApi } from './api/theme_fetch_api.js';
3
3
  import { FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME, SyncFeatureInitializer } from '@dreamcommerce/star_core';
4
4
  import { THEME_FETCH_FEATURE_NAME } from './theme_fetch_constants.js';
5
5
  import { ThemeFetchService } from './service/theme_fetch_service.js';
6
+ import { LOGGER_API_NAME } from '../../../../cli/utilities/features/logger/logger_constants.js';
6
7
  export class ThemeFetchInitializer extends SyncFeatureInitializer {
7
8
  static featureName = THEME_FETCH_FEATURE_NAME;
8
9
  init() {
9
10
  const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
11
+ const loggerApi = this.getApiSync(LOGGER_API_NAME);
10
12
  const themeFetchService = new ThemeFetchService({
11
13
  themeHttpApi: new ThemeFetchHttpApi(httpApi),
14
+ loggerApi,
12
15
  httpApi
13
16
  });
14
17
  return {
@@ -7,38 +7,64 @@ import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.
7
7
  import { ThemeInfoUtils } from '../../info/theme_info_utils.js';
8
8
  import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
9
9
  import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
10
- import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
10
+ import { AppError } from '../../../../../cli/utilities/features/logger/logs/app_error.js';
11
11
  export class ThemeInitService {
12
12
  #httpApi;
13
- constructor({ httpApi }) {
13
+ #loggerApi;
14
+ constructor({ httpApi, loggerApi }) {
14
15
  this.#httpApi = httpApi;
16
+ this.#loggerApi = loggerApi;
15
17
  }
16
- async initTheme({ action, credentials }) {
18
+ async initTheme({ action, credentials, sourceThemeId }) {
19
+ this.#loggerApi.info('Initializing theme', {
20
+ details: {
21
+ sourceThemeId
22
+ }
23
+ });
17
24
  const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true });
25
+ this.#loggerApi.debug('Temporary directory created.', { details: { path: tmpDir } });
26
+ this.#loggerApi.info('Downloading theme archive.');
18
27
  //TODO think global mechanism to handle when user ctr+c during download
19
28
  const { basename, filename } = await downloadFile({
20
29
  dist: tmpDir,
21
- request: this.#httpApi.initTheme(credentials.shopUrl, action.data).response
30
+ request: this.#httpApi.initTheme(credentials.shopUrl, action.data).response,
31
+ logger: this.#loggerApi
22
32
  });
33
+ this.#loggerApi.info('Theme archive downloaded.');
23
34
  const themeDir = join(process.cwd(), basename);
35
+ this.#loggerApi.info('Extracting theme archive.');
24
36
  await extractZip({
37
+ logger: this.#loggerApi,
25
38
  source: join(tmpDir, filename),
26
39
  dist: themeDir
27
40
  });
41
+ this.#loggerApi.info('Theme archive extracted.');
28
42
  try {
43
+ this.#loggerApi.debug('Updating theme files structure.');
29
44
  await ThemeFilesStructureUtils.updateFilesStructure(themeDir);
30
45
  }
31
46
  catch (err) {
32
47
  throw new AppError({
33
48
  message: `Failed to update files structure in theme directory: ${themeDir}`,
34
49
  code: 'theme_files_structure_update_error',
35
- stack: err.stack
50
+ error: err
36
51
  });
37
52
  }
53
+ this.#loggerApi.debug('Creating .gitignore file.');
38
54
  await ThemeMetaDataUtils.createGitIgnoreFile(themeDir);
55
+ this.#loggerApi.debug('Updating metadata file.');
39
56
  await ThemeMetaDataUtils.updateMetadataFileWithWorkUrl(themeDir, credentials.shopUrl);
40
- await new ThemeChecksums(themeDir).updateAllChecksums();
57
+ this.#loggerApi.debug('Updating theme checksums.');
58
+ await new ThemeChecksums({
59
+ themeDir,
60
+ loggerApi: this.#loggerApi
61
+ }).updateAllChecksums();
41
62
  const themeMetaData = await ThemeMetaDataUtils.getThemeMetadata(themeDir);
63
+ this.#loggerApi.info('Theme initialized successfully.', {
64
+ details: {
65
+ sourceThemeId
66
+ }
67
+ });
42
68
  return {
43
69
  themeId: themeMetaData.themeId,
44
70
  themeName: await ThemeInfoUtils.getThemeName(themeDir)
@@ -3,12 +3,15 @@ import { ThemeInitHttpApi } from './http/theme_init_http_api.js';
3
3
  import { ThemeInitApi } from './api/theme_init_api.js';
4
4
  import { ThemeInitService } from './service/theme_init_service.js';
5
5
  import { THEME_INIT_FEATURE_NAME } from './theme_init_constants.js';
6
+ import { LOGGER_API_NAME } from '../../../../cli/utilities/features/logger/logger_constants.js';
6
7
  export class ThemeInitInitializer extends SyncFeatureInitializer {
7
8
  static featureName = THEME_INIT_FEATURE_NAME;
8
9
  init() {
9
10
  const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
11
+ const loggerApi = this.getApiSync(LOGGER_API_NAME);
10
12
  const service = new ThemeInitService({
11
- httpApi: new ThemeInitHttpApi(httpApi)
13
+ httpApi: new ThemeInitHttpApi(httpApi),
14
+ loggerApi
12
15
  });
13
16
  return {
14
17
  cores: [