@shoper/cli 0.1.0-8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/build/cli/auth/cli_auth_errors_factory.js +1 -1
  2. package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +1 -1
  3. package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +1 -1
  4. package/build/cli/class/errors/file_system_errors_factory.js +1 -1
  5. package/build/cli/class/errors/http/http_errors_constants.js +1 -0
  6. package/build/cli/class/errors/{http_errors_factory.js → http/http_errors_factory.js} +3 -2
  7. package/build/cli/commands/auth/cli_auth_add_token_command.js +22 -19
  8. package/build/cli/commands/auth/cli_auth_commands_constants.js +3 -0
  9. package/build/cli/commands/auth/cli_auth_commands_utils.js +46 -0
  10. package/build/cli/commands/auth/cli_auth_list_tokens_command.js +19 -6
  11. package/build/cli/commands/auth/cli_auth_remove_token_command.js +36 -10
  12. package/build/cli/commands/auth/cli_auth_switch_token_command.js +19 -9
  13. package/build/cli/commands/auth/ui/invalid_token_index_error.js +11 -0
  14. package/build/cli/commands/auth/ui/missing_credentials_error.js +9 -0
  15. package/build/cli/commands/auth/ui/missing_token_index_error.js +19 -0
  16. package/build/cli/commands/cli_ui_dump_command.js +11 -0
  17. package/build/cli/commands/cli_update_command.js +13 -4
  18. package/build/cli/commands/commands_constants.js +2 -1
  19. package/build/cli/core/cli_setup.js +5 -1
  20. package/build/cli/features/controls/controls_constants.js +12 -0
  21. package/build/cli/features/controls/controls_dto_mappers.js +55 -0
  22. package/build/cli/features/controls/ui/controls_mappers.js +62 -0
  23. package/build/cli/features/controls/ui/form.js +4 -0
  24. package/build/cli/features/controls/ui/form_constants.js +7 -0
  25. package/build/cli/features/controls/validators/greater_eq_than_validator.js +5 -0
  26. package/build/cli/features/controls/validators/length_validator.js +6 -0
  27. package/build/cli/features/controls/validators/required_validator.js +5 -0
  28. package/build/cli/features/controls/validators/validator_constants.js +13 -0
  29. package/build/cli/features/execution_context/execution_context_service.js +5 -5
  30. package/build/cli/features/http_requester/http_requester_initializer.js +1 -1
  31. package/build/cli/hooks/authorization/ensure_authorization_hook.js +2 -2
  32. package/build/cli/hooks/authorization/ensure_authorization_hook_constants.js +8 -8
  33. package/build/index.js +37 -19
  34. package/build/theme/class/checksums/theme_checksums.js +174 -0
  35. package/build/theme/{features/theme/utils → class}/checksums/theme_checksums_error_factory.js +1 -1
  36. package/build/theme/class/checksums/theme_checksums_utils.js +17 -0
  37. package/build/theme/class/fetch_resources/fetch_resources.js +5 -3
  38. package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +1 -1
  39. package/build/theme/class/fetch_resources/fetch_resources_utils.js +4 -1
  40. package/build/theme/commands/delete/theme_delete_command.js +111 -0
  41. package/build/theme/commands/delete/ui/theme_deleted_successfully.js +15 -0
  42. package/build/theme/commands/delete/ui/theme_deletion_warning.js +10 -0
  43. package/build/theme/commands/info/theme_info_command.js +94 -0
  44. package/build/theme/commands/info/theme_info_command_utils.js +39 -0
  45. package/build/theme/commands/init/theme_init_command.js +97 -0
  46. package/build/theme/commands/init/ui/theme_created_success.js +15 -0
  47. package/build/theme/commands/list/theme_list_command.js +25 -0
  48. package/build/theme/commands/list/theme_list_command_utils.js +27 -0
  49. package/build/theme/commands/publish/theme_publish_command.js +92 -0
  50. package/build/theme/commands/pull/theme_pull_command.js +194 -0
  51. package/build/theme/commands/pull/ui/theme_pull_id_mismatch_error.js +7 -0
  52. package/build/theme/commands/pull/ui/theme_pull_unpublished_changes_warning.js +10 -0
  53. package/build/theme/commands/pull/ui/theme_pulled_success.js +5 -0
  54. package/build/theme/commands/push/theme_push_command.js +134 -0
  55. package/build/theme/commands/push/ui/theme_push_skip_into.js +7 -0
  56. package/build/theme/commands/push/ui/theme_pushed_success.js +5 -0
  57. package/build/theme/commands/push/ui/theme_unpermitted_actions_error.js +12 -0
  58. package/build/theme/commands/theme_commands_constants.js +4 -1
  59. package/build/theme/commands/theme_show_changes_command.js +1 -0
  60. package/build/theme/commands/theme_verify_command.js +8 -7
  61. package/build/theme/commands/ui/invalid_theme_id.js +11 -0
  62. package/build/theme/commands/ui/missing_theme_files.js +15 -0
  63. package/build/theme/commands/ui/missing_theme_id_error.js +13 -0
  64. package/build/theme/commands/ui/ouside_of_theme_directory_context_error.js +7 -0
  65. package/build/theme/commands/ui/theme_directory_context_error.js +7 -0
  66. package/build/theme/commands/ui/theme_work_url_mismatch.js +17 -0
  67. package/build/theme/commands/ui/unpermitted_command_error.js +18 -0
  68. package/build/theme/features/theme/actions/api/theme_actions_api.js +3 -0
  69. package/build/theme/features/theme/actions/service/theme_actions_service.js +15 -3
  70. package/build/theme/features/theme/actions/service/theme_actions_service_constants.js +1 -0
  71. package/build/theme/features/theme/actions/theme_actions_constants.js +3 -1
  72. package/build/theme/features/theme/actions/theme_actions_initializer.js +1 -1
  73. package/build/theme/features/theme/actions/theme_actions_utils.js +20 -7
  74. package/build/theme/features/theme/delete/api/theme_delete_api.js +13 -0
  75. package/build/theme/features/theme/delete/http/theme_delete_http_api.js +17 -0
  76. package/build/theme/features/theme/delete/service/theme_delete_service.js +31 -0
  77. package/build/theme/features/theme/delete/theme_delete_constants.js +2 -0
  78. package/build/theme/features/theme/delete/theme_delete_initalizer.js +20 -0
  79. package/build/theme/features/theme/fetch/service/theme_fetch_service.js +30 -10
  80. package/build/theme/features/theme/info/theme_info_utils.js +9 -0
  81. package/build/theme/features/theme/init/service/theme_init_service.js +9 -4
  82. package/build/theme/features/theme/merge/api/theme_merge_api.js +0 -12
  83. package/build/theme/features/theme/merge/service/theme_merge_service.js +20 -28
  84. package/build/theme/features/theme/push/service/theme_push_service.js +102 -73
  85. package/build/theme/features/theme/push/theme_push_constants.js +2 -0
  86. package/build/theme/features/theme/push/theme_push_errors_factory.js +7 -4
  87. package/build/theme/features/theme/push/theme_push_initializer.js +0 -3
  88. package/build/theme/features/theme/push/theme_push_utils.js +25 -0
  89. package/build/theme/features/theme/skinstore/api/theme_skinstore_api.js +19 -0
  90. package/build/theme/features/theme/skinstore/http/theme_skinstore_http_api.js +17 -0
  91. package/build/theme/features/theme/skinstore/service/theme_skinstore_service.js +32 -0
  92. package/build/theme/features/theme/skinstore/theme_publish_constants.js +4 -0
  93. package/build/theme/features/theme/skinstore/theme_skinstore_initialzier.js +20 -0
  94. package/build/theme/features/theme/utils/files_structure/theme_files_structure_utils.js +40 -0
  95. package/build/theme/features/theme/utils/hidden_directory/hidden_directory_utils.js +32 -0
  96. package/build/theme/features/theme/utils/meta_data/theme_meta_data_constants.js +1 -0
  97. package/build/theme/features/theme/utils/meta_data/theme_meta_data_error_factory.js +15 -0
  98. package/build/theme/features/theme/utils/meta_data/theme_meta_data_utils.js +39 -0
  99. package/build/theme/features/theme/utils/{directories → resources}/theme_resources_with_id_directory_utils.js +3 -14
  100. package/build/theme/features/theme/utils/theme_images_utils.js +5 -6
  101. package/build/theme/features/themes/list/api/themes_list_api.js +3 -0
  102. package/build/theme/features/themes/list/services/themes_list_service.js +13 -7
  103. package/build/theme/hooks/{ensure_theme_meta_data_untouched.js → ensure_theme_meta_data_untouched_hook.js} +2 -2
  104. package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_constants.js +1 -1
  105. package/build/theme/hooks/theme_checksums/{ensure_theme_current_checksums_up_to_date.js → ensure_theme_current_checksums_up_to_date_hook.js} +2 -5
  106. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +1 -0
  107. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook_constants.js +1 -0
  108. package/build/theme/index.js +11 -5
  109. package/build/theme/utils/directory_validator/directory_validator_constants.js +2 -6
  110. package/build/theme/utils/directory_validator/directory_validator_utils.js +18 -38
  111. package/build/ui/box.js +2 -0
  112. package/build/ui/color_constants.js +30 -0
  113. package/build/ui/command.js +6 -0
  114. package/build/ui/file_name.js +6 -0
  115. package/build/ui/flag.js +6 -0
  116. package/build/ui/icons/error_icon.js +7 -0
  117. package/build/ui/icons/info_icon.js +7 -0
  118. package/build/ui/icons/success_icon.js +7 -0
  119. package/build/ui/icons/warning_icon.js +7 -0
  120. package/build/ui/link.js +8 -0
  121. package/build/ui/list/list.js +10 -0
  122. package/build/ui/list/list_constants.js +4 -0
  123. package/build/ui/list/list_item.js +11 -0
  124. package/build/ui/message_box/error.js +4 -0
  125. package/build/ui/message_box/info.js +4 -0
  126. package/build/ui/message_box/message_box.js +11 -0
  127. package/build/ui/message_box/message_box_constants.js +24 -0
  128. package/build/ui/message_box/success.js +4 -0
  129. package/build/ui/message_box/warning.js +4 -0
  130. package/build/ui/prompts/prompt_confirmation.js +11 -0
  131. package/build/ui/prompts/prompt_input.js +10 -0
  132. package/build/ui/table/t_cell.js +7 -0
  133. package/build/ui/table/t_header.js +9 -0
  134. package/build/ui/table/t_row.js +5 -0
  135. package/build/ui/table/table.js +18 -0
  136. package/build/ui/text.js +2 -0
  137. package/build/ui/tip.js +9 -0
  138. package/build/ui/ui_dump/ui_component_box.js +9 -0
  139. package/build/ui/ui_dump/ui_dump.js +53 -0
  140. package/build/ui/ui_dump/ui_dump_constants.js +21 -0
  141. package/build/ui/ui_utils.js +11 -0
  142. package/build/ui/validation_errors/validation_error_content.js +19 -0
  143. package/build/ui/validation_errors/validation_errors.js +21 -0
  144. package/build/ui/validation_errors/validation_errors_utils.js +17 -0
  145. package/build/utils/checksums/checksums_utils.js +9 -26
  146. package/build/utils/download_file/download_file_errors_factory.js +1 -1
  147. package/build/utils/download_file/download_file_utils.js +4 -2
  148. package/build/utils/fs/errors/stream_read_error.js +1 -1
  149. package/build/utils/fs/errors/stream_write_error.js +1 -1
  150. package/build/utils/fs/fs_utils.js +17 -3
  151. package/build/utils/path_utils.js +20 -1
  152. package/build/utils/platform_utils.js +3 -0
  153. package/build/utils/zip/create_zip_utils.js +1 -1
  154. package/build/utils/zip/errors/create_zip_error.js +1 -1
  155. package/build/utils/zip/errors/open_zip_error.js +1 -1
  156. package/oclif.config.js +2 -2
  157. package/package.json +15 -8
  158. package/build/theme/commands/theme_init_command.js +0 -53
  159. package/build/theme/commands/theme_list_command.js +0 -16
  160. package/build/theme/commands/theme_pull_command.js +0 -124
  161. package/build/theme/commands/theme_push_command.js +0 -65
  162. package/build/theme/features/theme/directory/theme_directory_utils.js +0 -76
  163. package/build/theme/features/theme/publish/theme_publish_constants.js +0 -2
  164. package/build/theme/features/theme/utils/checksums/theme_checksums_utils.js +0 -94
  165. /package/build/cli/{features → class}/caches/cache_factory.js +0 -0
  166. /package/build/cli/{features → class}/caches/json_cache/json_cache.js +0 -0
  167. /package/build/cli/{features → class}/caches/memory_cache.js +0 -0
  168. /package/build/cli/class/errors/{app_error → app}/app_error.js +0 -0
  169. /package/build/cli/class/errors/{app_error → app}/app_error_constants.js +0 -0
  170. /package/build/theme/features/theme/{publish → skinstore}/theme_publish_utils.js +0 -0
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { Info } from '../../../../ui/message_box/info.js';
3
+ import { Text } from '../../../../ui/text.js';
4
+ export const ThemePushSkipInfo = () => {
5
+ return (React.createElement(Info, null,
6
+ React.createElement(Text, null, "Nothing to push, skipped.")));
7
+ };
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { Success } from '../../../../ui/message_box/success.js';
3
+ export const ThemePushedSuccess = ({ themeName }) => {
4
+ return React.createElement(Success, { header: `Success: Theme "${themeName}" was pushed` });
5
+ };
@@ -0,0 +1,12 @@
1
+ import { List } from '../../../../ui/list/list.js';
2
+ import { Error } from '../../../../ui/message_box/error.js';
3
+ import { Text } from '../../../../ui/text.js';
4
+ import React from 'react';
5
+ export const ThemeUnpermittedActionsError = ({ unpermittedActions }) => {
6
+ const items = unpermittedActions.map((action) => ({
7
+ content: `${action.type} - ${action.relativePath}`
8
+ }));
9
+ return (React.createElement(Error, { header: "Theme validation error" },
10
+ React.createElement(Text, null, "Theme file structure is not valid. The following actions are not permitted:"),
11
+ React.createElement(List, { items: items })));
12
+ };
@@ -4,5 +4,8 @@ export const THEME_COMMANDS_NAME = {
4
4
  init: 'theme:init',
5
5
  push: 'theme:push',
6
6
  showChanges: 'theme:show-changes',
7
- verify: 'theme:verify'
7
+ verify: 'theme:verify',
8
+ info: 'theme:info',
9
+ delete: 'theme:delete',
10
+ publish: 'theme:publish'
8
11
  };
@@ -9,6 +9,7 @@ import { join } from '../../utils/path_utils.js';
9
9
  import ora from 'ora';
10
10
  export class ThemeShowChangesCommand extends BaseThemeCommand {
11
11
  static description = 'Show local theme changes';
12
+ static hidden = true;
12
13
  async run() {
13
14
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
14
15
  const credentials = cliAuthApi.getCredentials();
@@ -1,12 +1,13 @@
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 { ThemeDirectoryUtils } from '../features/theme/directory/theme_directory_utils.js';
5
4
  import { mapToPermissionsTree } from '../utils/directory_validator/directory_validator_utils.js';
6
5
  import { mapChecksumToTree } from '../../utils/checksums/checksums_utils.js';
7
- import { ThemeChecksumsUtils } from '../features/theme/utils/checksums/theme_checksums_utils.js';
6
+ import { ThemeFilesStructureUtils } from '../features/theme/utils/files_structure/theme_files_structure_utils.js';
7
+ import { ThemeChecksums } from '../class/checksums/theme_checksums.js';
8
8
  export class ThemeVerifyCommand extends BaseThemeCommand {
9
9
  static description = 'Verify theme files structure';
10
+ static hidden = true;
10
11
  async run() {
11
12
  const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
12
13
  const credentials = cliAuthApi.getCredentials();
@@ -16,13 +17,13 @@ export class ThemeVerifyCommand extends BaseThemeCommand {
16
17
  const executionContext = await executionContextApi.getExecutionContext();
17
18
  if (executionContext.type !== EXECUTION_CONTEXTS.theme)
18
19
  this.error('You cannot run this command outside theme context.');
19
- const checksums = await ThemeChecksumsUtils.getThemeInitialChecksums(executionContext.themeRootDir);
20
- const permissions = await ThemeDirectoryUtils.getFilesPermissions(executionContext.themeRootDir);
21
- if (!checksums || !permissions)
20
+ const themeChecksums = new ThemeChecksums(executionContext.themeRootDir);
21
+ const permissions = await ThemeFilesStructureUtils.getFilesPermissions(executionContext.themeRootDir);
22
+ if (!themeChecksums || !permissions)
22
23
  this.error('Theme checksums or permissions not found. Please ensure you are in the correct theme directory.');
23
24
  try {
24
- const validationResult = await ThemeDirectoryUtils.validateThemeDirectoryStructure({
25
- checksums: mapChecksumToTree(checksums),
25
+ const validationResult = await ThemeFilesStructureUtils.validateThemeDirectoryStructure({
26
+ checksums: mapChecksumToTree(await themeChecksums.getInitialChecksums()),
26
27
  permissions: mapToPermissionsTree(permissions),
27
28
  rootDirectory: executionContext.themeRootDir
28
29
  });
@@ -0,0 +1,11 @@
1
+ import { Error } from '../../../ui/message_box/error.js';
2
+ import { Tip } from '../../../ui/tip.js';
3
+ import { Command } from '../../../ui/command.js';
4
+ import React from 'react';
5
+ export const InvalidThemeIdError = ({ themeId }) => {
6
+ return (React.createElement(Error, { header: `Error: Invalid theme ID: ${themeId}` },
7
+ React.createElement(Tip, null,
8
+ "Run ",
9
+ React.createElement(Command, null, "shoper theme list"),
10
+ " to see available theme IDs.")));
11
+ };
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { Error } from '../../../ui/message_box/error.js';
3
+ import { Text } from '../../../ui/text.js';
4
+ import { List } from '../../../ui/list/list.js';
5
+ import { Command } from '../../../ui/command.js';
6
+ export const MissingThemeFiles = ({ files }) => {
7
+ return (React.createElement(Error, { header: `Error: Detected local changes in: ${Array.isArray(files) ? '' : files}` },
8
+ Array.isArray(files) ? (React.createElement(List, { items: files.map((file) => ({
9
+ content: file
10
+ })) })) : null,
11
+ React.createElement(Text, null,
12
+ "This file is managed by the system and should not be modified locally. Please revert it to its original version manually or run",
13
+ React.createElement(Command, null, "shoper theme pull"),
14
+ " to download the correct version from the server.")));
15
+ };
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ import { Error } from '../../../ui/message_box/error.js';
3
+ import { Box } from '../../../ui/box.js';
4
+ import { Tip } from '../../../ui/tip.js';
5
+ import { Command } from '../../../ui/command.js';
6
+ export const MissingThemeIdError = ({ children }) => {
7
+ return (React.createElement(Error, { header: "Error: Missing theme ID." },
8
+ React.createElement(Box, null, children),
9
+ React.createElement(Tip, null,
10
+ "Run ",
11
+ React.createElement(Command, null, "shoper theme list"),
12
+ " to see available themes and their IDs.")));
13
+ };
@@ -0,0 +1,7 @@
1
+ import { Error } from '../../../ui/message_box/error.js';
2
+ import { Text } from '../../../ui/text.js';
3
+ import React from 'react';
4
+ export const OutsideOfThemeDirectoryContextError = () => {
5
+ return (React.createElement(Error, null,
6
+ React.createElement(Text, null, "Error: Cannot run this command outside of a theme directory. Please run it inside a theme directory.")));
7
+ };
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ import { Error } from '../../../ui/message_box/error.js';
3
+ import { Text } from '../../../ui/text.js';
4
+ export const ThemeDirectoryContextError = () => {
5
+ return (React.createElement(Error, null,
6
+ React.createElement(Text, null, "Error: Cannot run this command inside a theme directory. Please run it outside of a theme directory.")));
7
+ };
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { Error } from '../../../ui/message_box/error.js';
3
+ import { Command } from '../../../ui/command.js';
4
+ import { Tip } from '../../../ui/tip.js';
5
+ import { Text } from '../../../ui/text.js';
6
+ export const ThemeWorkUrlMismatch = ({ command }) => {
7
+ return (React.createElement(Error, { header: `Error: This theme belongs to a different store.` },
8
+ React.createElement(Text, null,
9
+ "Switch to the correct token to ",
10
+ command,
11
+ " this theme."),
12
+ React.createElement(Tip, null,
13
+ React.createElement(Text, null,
14
+ "Run ",
15
+ React.createElement(Command, null, "shoper theme auth token switch"),
16
+ " to change your token"))));
17
+ };
@@ -0,0 +1,18 @@
1
+ import { Text } from '../../../ui/text.js';
2
+ import { Tip } from '../../../ui/tip.js';
3
+ import { Command } from '../../../ui/command.js';
4
+ import { Error } from '../../../ui/message_box/error.js';
5
+ import React from 'react';
6
+ export const UnpermittedCommandError = ({ commandName, themeId }) => {
7
+ return (React.createElement(Error, null,
8
+ React.createElement(Text, null,
9
+ "You cannot ",
10
+ commandName,
11
+ " theme with id ",
12
+ themeId,
13
+ ". Please check if the theme exists or if you have the necessary permissions."),
14
+ React.createElement(Tip, null,
15
+ "Run ",
16
+ React.createElement(Command, null, "shoper auth list-tokens"),
17
+ " to see available token index values.")));
18
+ };
@@ -16,4 +16,7 @@ export class ThemeActionsApi extends FeatureApi {
16
16
  clearThemesActions(props) {
17
17
  return this.#service.clearThemesActions(props);
18
18
  }
19
+ removeThemeActions(props) {
20
+ return this.#service.removeThemeActions(props);
21
+ }
19
22
  }
@@ -1,7 +1,8 @@
1
1
  import { STORE_THEMES_ACTIONS_TTL } from './theme_actions_service_constants.js';
2
- import { AppError } from '../../../../../cli/class/errors/app_error/app_error.js';
2
+ import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
3
3
  import { getNMinutesFromNow } from '../../../../../utils/date_utils.js';
4
4
  import { computeChecksum } from '../../../../../utils/checksums/checksums_utils.js';
5
+ import { THEME_ACTION_NOT_FOUND_ERROR_CODE, THEME_ACTION_NOTS_FOUND_ERROR_CODE } from '../theme_actions_constants.js';
5
6
  export class ThemeActionsService {
6
7
  #themesListApi;
7
8
  #themesActionsStore;
@@ -13,17 +14,28 @@ export class ThemeActionsService {
13
14
  const storeActions = this.#themesActionsStore.get(this._getKey(credentials.shopUrl));
14
15
  if (!storeActions)
15
16
  throw new AppError({
16
- code: 'theme_actions_not_found',
17
+ code: THEME_ACTION_NOTS_FOUND_ERROR_CODE,
17
18
  message: `Theme actions for store ${credentials.shopUrl} not found.`
18
19
  });
19
20
  const actions = storeActions.actions[themeId];
20
21
  if (!actions)
21
22
  throw new AppError({
22
- code: 'theme_action_not_found',
23
+ code: THEME_ACTION_NOT_FOUND_ERROR_CODE,
23
24
  message: `Theme action for theme ${themeId} not found.`
24
25
  });
25
26
  return actions[actionType];
26
27
  }
28
+ removeThemeActions({ themeId, credentials }) {
29
+ const storeActions = this.#themesActionsStore.get(this._getKey(credentials.shopUrl));
30
+ if (!storeActions || !storeActions.actions[themeId]) {
31
+ throw new AppError({
32
+ code: THEME_ACTION_NOTS_FOUND_ERROR_CODE,
33
+ message: `Theme actions for store ${credentials.shopUrl} not found.`
34
+ });
35
+ }
36
+ delete storeActions.actions[themeId];
37
+ this.#themesActionsStore.set(this._getKey(credentials.shopUrl), storeActions);
38
+ }
27
39
  async ensureThemesActions({ credentials, themeId }) {
28
40
  if (!themeId)
29
41
  return;
@@ -1,2 +1,3 @@
1
1
  export const STORE_THEMES_ACTIONS_TTL = 10;
2
2
  export const THEME_WILDCARD_ACTION_NAME = '*';
3
+ export const THEME_ALL_ACTIONS_NAME = 'all';
@@ -6,10 +6,12 @@ export const THEME_ACTIONS_TYPES = {
6
6
  push: 'push',
7
7
  pull: 'pull',
8
8
  delete: 'delete',
9
- publish_form: 'publish_form',
9
+ publishForm: 'publish_form',
10
10
  publish: 'publish'
11
11
  };
12
12
  export const THEME_ACTION_DATA_TYPE = {
13
13
  file: 'file',
14
14
  zip: 'zip'
15
15
  };
16
+ export const THEME_ACTION_NOT_FOUND_ERROR_CODE = 'theme_action_not_found';
17
+ export const THEME_ACTION_NOTS_FOUND_ERROR_CODE = 'theme_actions_not_found';
@@ -1,6 +1,6 @@
1
1
  import { AsyncFeatureInitializer, FEATURE_CORES_TYPES } from '@dreamcommerce/star_core';
2
2
  import { THEMES_LIST_API_NAME } from '../../themes/list/themes_list_constants.js';
3
- import { JsonCache } from '../../../../cli/features/caches/json_cache/json_cache.js';
3
+ import { JsonCache } from '../../../../cli/class/caches/json_cache/json_cache.js';
4
4
  import { CLI_DATA_DIRECTORY_API_NAME } from '../../../../cli/features/data_directory/cli_data_directory_constants.js';
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';
@@ -1,8 +1,21 @@
1
- export const getFilesGlobsThatMatchesActionName = (actionType, actionValue, filesStructure) => {
2
- return Object.entries(filesStructure).reduce((acc, [filePath, fileStructureItem]) => {
3
- if (fileStructureItem._links?.[actionType] === actionValue) {
4
- return [...acc, filePath];
1
+ import { THEME_ALL_ACTIONS_NAME } from './service/theme_actions_service_constants.js';
2
+ import { toUnixPath } from '../../../../utils/path_utils.js';
3
+ export class ThemeActionsUtils {
4
+ static getFilesGlobsThatMatchesActionName({ filesStructure, actionValue, actionType }) {
5
+ return Object.entries(filesStructure).reduce((acc, [filePath, fileStructureItem]) => {
6
+ if (fileStructureItem._links?.[actionType] && this._doesActionValueMatch(fileStructureItem._links[actionType], actionValue)) {
7
+ return [...acc, toUnixPath(filePath)];
8
+ }
9
+ return acc;
10
+ }, []);
11
+ }
12
+ static _doesActionValueMatch(currentActionValue, valuesToMatch) {
13
+ if (typeof valuesToMatch === 'string') {
14
+ return currentActionValue === valuesToMatch || valuesToMatch === THEME_ALL_ACTIONS_NAME;
5
15
  }
6
- return acc;
7
- }, []);
8
- };
16
+ if (Array.isArray(valuesToMatch)) {
17
+ return valuesToMatch.includes(currentActionValue) || valuesToMatch.includes(THEME_ALL_ACTIONS_NAME);
18
+ }
19
+ return false;
20
+ }
21
+ }
@@ -0,0 +1,13 @@
1
+ import { FeatureApi } from '@dreamcommerce/star_core';
2
+ import { THEME_DELETE_API_NAME } from '../theme_delete_constants.js';
3
+ export class ThemeDeleteApi extends FeatureApi {
4
+ moduleName = THEME_DELETE_API_NAME;
5
+ #service;
6
+ constructor(service) {
7
+ super();
8
+ this.#service = service;
9
+ }
10
+ async deleteTheme(props) {
11
+ return this.#service.deleteTheme(props);
12
+ }
13
+ }
@@ -0,0 +1,17 @@
1
+ export class ThemeDeleteHttpApi {
2
+ #httpApi;
3
+ constructor(httpApi) {
4
+ this.#httpApi = httpApi;
5
+ }
6
+ deleteTheme({ shopUrl, actionData }) {
7
+ const { method, url } = actionData;
8
+ return this.#httpApi.fetch({
9
+ url: `${shopUrl}${url}`,
10
+ method,
11
+ sanitizeOptions: {
12
+ disable: true
13
+ },
14
+ isPrivate: true
15
+ });
16
+ }
17
+ }
@@ -0,0 +1,31 @@
1
+ import { HttpErrorsFactory } from '../../../../../cli/class/errors/http/http_errors_factory.js';
2
+ import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/download_file_errors_factory.js';
3
+ import { STATUS_CODES } from '@dreamcommerce/star_core';
4
+ export class ThemeDeleteService {
5
+ #httpApi;
6
+ constructor(httpApi) {
7
+ this.#httpApi = httpApi;
8
+ }
9
+ async deleteTheme({ actionData, credentials }) {
10
+ try {
11
+ const { response: request } = this.#httpApi.deleteTheme({ actionData, shopUrl: credentials.shopUrl });
12
+ const response = await request;
13
+ if (response?.status !== STATUS_CODES.ok)
14
+ return;
15
+ return response?.data;
16
+ }
17
+ catch (err) {
18
+ //TODO to basic class
19
+ switch (err.response?.status) {
20
+ case 403:
21
+ throw HttpErrorsFactory.createForbiddenError();
22
+ case 401:
23
+ throw HttpErrorsFactory.createUnauthorizedError();
24
+ case 404:
25
+ throw HttpErrorsFactory.createNotFoundError();
26
+ default:
27
+ throw DownloadFileErrorsFactory.downloadError(err.response.status);
28
+ }
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,2 @@
1
+ export const THEME_DELETE_FEATURE_NAME = 'ThemeDelete';
2
+ export const THEME_DELETE_API_NAME = 'ThemeDeleteApi';
@@ -0,0 +1,20 @@
1
+ import { FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME, SyncFeatureInitializer } from '@dreamcommerce/star_core';
2
+ import { ThemeDeleteApi } from './api/theme_delete_api.js';
3
+ import { ThemeDeleteService } from './service/theme_delete_service.js';
4
+ import { ThemeDeleteHttpApi } from './http/theme_delete_http_api.js';
5
+ import { THEME_DELETE_FEATURE_NAME } from './theme_delete_constants.js';
6
+ export class ThemeDeleteInitializer extends SyncFeatureInitializer {
7
+ static featureName = THEME_DELETE_FEATURE_NAME;
8
+ init() {
9
+ const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
10
+ const service = new ThemeDeleteService(new ThemeDeleteHttpApi(httpApi));
11
+ return {
12
+ cores: [
13
+ {
14
+ type: FEATURE_CORES_TYPES.api,
15
+ instance: new ThemeDeleteApi(service)
16
+ }
17
+ ]
18
+ };
19
+ }
20
+ }
@@ -4,17 +4,18 @@ import { downloadFile } from '../../../../../utils/download_file/download_file_u
4
4
  import { extractZip } from '../../../../../utils/zip/extract_zip_utils.js';
5
5
  import { join } from '../../../../../utils/path_utils.js';
6
6
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
7
- import { getResources, mapResourcesToTree } from '../../../../class/fetch_resources/fetch_resources_utils.js';
7
+ import { getResources, mapResourcesToTree, removeOldResources } from '../../../../class/fetch_resources/fetch_resources_utils.js';
8
8
  import { FetchResources } from '../../../../class/fetch_resources/fetch_resources.js';
9
9
  import { jsonIndentTransform } from '../../../../../utils/stream_transforms/json_indent_transform.js';
10
- import { ThemeDirectoryUtils } from '../../directory/theme_directory_utils.js';
11
10
  import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../theme_constants.js';
12
11
  import { THEME_FILES_LIST_FILE_NAME } from '../../push/theme_push_constants.js';
13
12
  import { JSON_FILE_INDENT } from '../../../../../cli/cli_constants.js';
14
- import { computeChecksumsFromSource } from '../../../../../utils/checksums/checksums_utils.js';
15
- import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
16
13
  import { createWriteStream } from 'node:fs';
17
- import { AppError } from '../../../../../cli/class/errors/app_error/app_error.js';
14
+ import { AppError } from '../../../../../cli/class/errors/app/app_error.js';
15
+ import { THEME_ACTIONS_TYPES } from '../../actions/theme_actions_constants.js';
16
+ import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
17
+ import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
18
+ import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
18
19
  export class ThemeFetchService {
19
20
  #themeHttpApi;
20
21
  #httpApi;
@@ -53,14 +54,17 @@ export class ThemeFetchService {
53
54
  });
54
55
  }
55
56
  await this._createGitIgnoreFile(themeDir);
56
- const checksums = await computeChecksumsFromSource(themeDir);
57
- await ThemeChecksumsUtils.createThemeChecksumsFiles(themeDir, checksums);
57
+ await this._updateMetadataFileWithWorkUrl(themeDir, credentials.shopUrl);
58
+ /**
59
+ * moze to nie powinno lezec tutaj :?
60
+ */
61
+ await new ThemeChecksums(themeDir).updateAllChecksums();
58
62
  return {
59
63
  name: basename
60
64
  };
61
65
  }
62
66
  async _updateFilesStructure(themeDir) {
63
- const fileStructure = await ThemeDirectoryUtils.getThemeFilesStructure(themeDir);
67
+ const fileStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(themeDir);
64
68
  const checksumsFiles = [
65
69
  `${SHOPER_THEME_METADATA_DIR}/${THEME_INITIAL_CHECKSUMS_FILE_NAME}`,
66
70
  `${SHOPER_THEME_METADATA_DIR}/${THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME}`,
@@ -76,7 +80,15 @@ export class ThemeFetchService {
76
80
  }
77
81
  };
78
82
  });
79
- [THEME_FILES_LIST_FILE_NAME, '.gitignore'].forEach((fileName) => {
83
+ fileStructure[THEME_FILES_LIST_FILE_NAME] = {
84
+ permissions: {
85
+ canAdd: true,
86
+ canEdit: true,
87
+ canDelete: true
88
+ },
89
+ _links: { [THEME_ACTIONS_TYPES.push]: '*' }
90
+ };
91
+ ['.gitignore'].forEach((fileName) => {
80
92
  fileStructure[fileName] = {
81
93
  permissions: {
82
94
  canAdd: true,
@@ -85,9 +97,17 @@ export class ThemeFetchService {
85
97
  }
86
98
  };
87
99
  });
88
- await ThemeDirectoryUtils.writeThemeFilesStructure(themeDir, fileStructure);
100
+ await ThemeFilesStructureUtils.writeThemeFilesStructure(themeDir, fileStructure);
101
+ }
102
+ async _updateMetadataFileWithWorkUrl(themeDir, workUrl) {
103
+ const shopMetadata = await ThemeMetaDataUtils.getThemeMetadata(themeDir);
104
+ await ThemeMetaDataUtils.updateThemeMetadata(themeDir, {
105
+ ...shopMetadata,
106
+ workUrl
107
+ });
89
108
  }
90
109
  async fetchResources(shopUrl, dist, resources) {
110
+ await removeOldResources(dist, resources);
91
111
  const resourcesTree = mapResourcesToTree(resources);
92
112
  await Promise.all(Object.keys(resourcesTree).map((resource) => new FetchResources(this.#httpApi).fetchResources({
93
113
  resourcesPart: resourcesTree[resource],
@@ -0,0 +1,9 @@
1
+ import { readJSONFile } from '../../../../utils/fs/fs_utils.js';
2
+ import { join } from '../../../../utils/path_utils.js';
3
+ export class ThemeInfoUtils {
4
+ static async getThemeName(themeDir) {
5
+ //TODO - wziasc z themeList a to wywalic
6
+ const themeDetails = await readJSONFile(join(themeDir, 'settings', 'details.json'));
7
+ return themeDetails.name ?? 'Storefront';
8
+ }
9
+ }
@@ -3,8 +3,9 @@ import process from 'process';
3
3
  import tmp from 'tmp-promise';
4
4
  import { downloadFile } from '../../../../../utils/download_file/download_file_utils.js';
5
5
  import { extractZip } from '../../../../../utils/zip/extract_zip_utils.js';
6
- import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
7
- import { computeChecksumsFromSource } from '../../../../../utils/checksums/checksums_utils.js';
6
+ import { ThemeMetaDataUtils } from '../../utils/meta_data/theme_meta_data_utils.js';
7
+ import { ThemeInfoUtils } from '../../info/theme_info_utils.js';
8
+ import { ThemeChecksums } from '../../../../../theme/class/checksums/theme_checksums.js';
8
9
  export class ThemeInitService {
9
10
  #httpApi;
10
11
  constructor({ httpApi }) {
@@ -22,7 +23,11 @@ export class ThemeInitService {
22
23
  source: join(tmpDir, filename),
23
24
  dist: distDir
24
25
  });
25
- const checksums = await computeChecksumsFromSource(distDir);
26
- await ThemeChecksumsUtils.createThemeChecksumsFiles(join(process.cwd(), basename), checksums);
26
+ new ThemeChecksums(distDir).updateAllChecksums();
27
+ const themeMetaData = await ThemeMetaDataUtils.getThemeMetadata(distDir);
28
+ return {
29
+ themeId: themeMetaData.themeId,
30
+ themeName: await ThemeInfoUtils.getThemeName(distDir)
31
+ };
27
32
  }
28
33
  }
@@ -7,22 +7,10 @@ export class ThemeMergeApi extends FeatureApi {
7
7
  super();
8
8
  this.#service = service;
9
9
  }
10
- hasThemeBeenModified(themeRootDir) {
11
- return this.#service.hasThemeBeenModified(themeRootDir);
12
- }
13
10
  getChangesBetweenThemes(theme1, theme2) {
14
11
  return this.#service.getChangesBetweenThemes(theme1, theme2);
15
12
  }
16
13
  applyChanges(fromTheme, toTheme, changes) {
17
14
  return this.#service.applyChanges(fromTheme, toTheme, changes);
18
15
  }
19
- hasFileBeenCreated(path, executionContext) {
20
- return this.#service.hasFileBeenCreated(path, executionContext);
21
- }
22
- hasFileBeenRemoved(path, executionContext) {
23
- return this.#service.hasFileBeenRemoved(path, executionContext);
24
- }
25
- hasFileBeenModified(path, executionContext) {
26
- return this.#service.hasFileBeenModified(path, executionContext);
27
- }
28
16
  }
@@ -1,22 +1,21 @@
1
1
  import FSTree from 'fs-tree-diff';
2
- import { join } from '../../../../../utils/path_utils.js';
3
- import { computeChecksumsFromSource, computeFileChecksum } from '../../../../../utils/checksums/checksums_utils.js';
4
- import { copyFile, copyFileSync, fileExists } from '../../../../../utils/fs/fs_utils.js';
5
- import { ThemeChecksumsUtils } from '../../utils/checksums/theme_checksums_utils.js';
2
+ import { copyFileSync, getAllDirectoriesNamesInside } from '../../../../../utils/fs/fs_utils.js';
6
3
  import walkSync from 'walk-sync';
4
+ import { ThemeChecksums } from '../../../../class/checksums/theme_checksums.js';
5
+ import { ThemeFilesStructureUtils } from '../../utils/files_structure/theme_files_structure_utils.js';
7
6
  import { SHOPER_THEME_METADATA_DIR } from '../../../../constants/directory_contstants.js';
7
+ import { join, platformSeparator } from '../../../../../utils/path_utils.js';
8
8
  export class ThemeMergeService {
9
9
  async applyChanges(fromTheme, toTheme, changes) {
10
10
  FSTree.applyPatch(fromTheme, toTheme, changes, {
11
11
  create(inputPath, outputPath) {
12
- copyFile(inputPath, outputPath);
12
+ copyFileSync(inputPath, outputPath);
13
13
  },
14
14
  change(inputPath, outputPath) {
15
15
  copyFileSync(inputPath, outputPath);
16
16
  }
17
17
  });
18
- const checksums = await computeChecksumsFromSource(toTheme);
19
- await ThemeChecksumsUtils.createThemeChecksumsFiles(toTheme, checksums);
18
+ new ThemeChecksums(toTheme).updateAllChecksums();
20
19
  }
21
20
  async getChangesBetweenThemes(theme1, theme2) {
22
21
  const theme1Tree = new FSTree({
@@ -25,32 +24,25 @@ export class ThemeMergeService {
25
24
  const theme2Tree = new FSTree({
26
25
  entries: walkSync.entries(theme2)
27
26
  });
28
- const theme1Checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(theme1);
29
- const theme2Checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(theme2);
27
+ const theme1Checksums = new ThemeChecksums(theme1);
28
+ const theme2Checksums = new ThemeChecksums(theme2);
29
+ const userDirectories = await this._getUserRootDirectories(theme2);
30
30
  return theme2Tree
31
31
  .calculatePatch(theme1Tree, (entryA, entryB) => {
32
32
  if (entryA.isDirectory() && entryB.isDirectory())
33
33
  return true;
34
- return theme1Checksums[entryA.relativePath] === theme2Checksums[entryB.relativePath];
34
+ return (theme1Checksums.getCurrentChecksumFromPathSync(entryA.relativePath) ===
35
+ theme2Checksums.getCurrentChecksumFromPathSync(entryB.relativePath));
35
36
  })
36
- .filter(([, name]) => !name.startsWith(SHOPER_THEME_METADATA_DIR));
37
- }
38
- async hasThemeBeenModified(themeRootDir) {
39
- const initialChecksums = await ThemeChecksumsUtils.getInitialChecksumsVerification(themeRootDir);
40
- const currentChecksums = await ThemeChecksumsUtils.getThemeCurrentChecksumsVerification(themeRootDir);
41
- return initialChecksums !== currentChecksums;
42
- }
43
- async hasFileBeenCreated(path, executionContext) {
44
- const checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(executionContext.themeRootDir);
45
- return checksums[path] === undefined && (await fileExists(join(executionContext.themeRootDir, path)));
46
- }
47
- async hasFileBeenRemoved(path, executionContext) {
48
- const checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(executionContext.themeRootDir);
49
- return !(await fileExists(join(executionContext.themeRootDir, path))) && !!checksums[path];
37
+ .filter(([_, name]) => {
38
+ return !name.startsWith(SHOPER_THEME_METADATA_DIR) && !userDirectories.some((userDir) => name.startsWith(userDir));
39
+ });
50
40
  }
51
- async hasFileBeenModified(path, executionContext) {
52
- const checksums = await ThemeChecksumsUtils.getThemeCurrentChecksums(executionContext.themeRootDir);
53
- const currentChecksum = await computeFileChecksum(join(executionContext.themeRootDir, path));
54
- return !!checksums[path] && checksums[path] !== currentChecksum;
41
+ async _getUserRootDirectories(themeDir) {
42
+ const filesStructure = await ThemeFilesStructureUtils.getThemeRootDirectories(themeDir);
43
+ return (await getAllDirectoriesNamesInside(themeDir, {
44
+ recursive: false,
45
+ hidden: true
46
+ })).filter((directory) => !filesStructure.includes(join(directory, platformSeparator)));
55
47
  }
56
48
  }