@shoper/cli 0.5.2 → 0.6.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.
- package/README.md +4 -2
- package/build/cli/auth/cli_auth_errors_factory.js +1 -1
- package/build/cli/auth/cli_auth_initializer.js +6 -1
- package/build/cli/auth/service/cli_auth_service.js +11 -2
- package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +1 -1
- package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +6 -1
- package/build/cli/auth/tokens/service/cli_auth_tokens_service.js +8 -1
- package/build/cli/class/base_command.js +15 -1
- package/build/cli/class/cli_help.js +24 -0
- package/build/cli/class/errors/file_system_errors_factory.js +3 -3
- package/build/cli/class/errors/http/http_errors_factory.js +1 -1
- package/build/cli/commands/auth/cli_auth_add_token_command.js +5 -0
- package/build/cli/commands/auth/cli_auth_list_tokens_command.js +20 -11
- package/build/cli/commands/auth/cli_auth_logout_command.js +5 -0
- package/build/cli/commands/auth/cli_auth_remove_token_command.js +5 -0
- package/build/cli/commands/auth/cli_auth_switch_token_command.js +8 -0
- package/build/cli/commands/cli_update_command.js +5 -0
- package/build/cli/core/cli_setup.js +5 -13
- package/build/cli/features/execution_context/execution_context_service.js +2 -0
- package/build/cli/features/version/service/cli_version_service.js +2 -2
- package/build/cli/hooks/authorization/ensure_authorization_hook.js +9 -2
- package/build/cli/hooks/ensure_cli_initialized_hook.js +1 -6
- package/build/cli/hooks/ensure_logs_flushed_hook.js +7 -0
- package/build/cli/{features → utilities/features}/http_requester/http_client.js +2 -2
- package/build/cli/{features → utilities/features}/http_requester/http_requester_initializer.js +1 -1
- package/build/cli/utilities/features/logger/api/logger_api.js +28 -0
- package/build/cli/utilities/features/logger/logger_constants.js +7 -0
- package/build/cli/utilities/features/logger/logger_initializer.js +44 -0
- package/build/cli/utilities/features/logger/logs/app_error.js +14 -0
- package/build/cli/utilities/features/logger/logs/app_log.js +40 -0
- package/build/cli/{class/errors/app/app_error_constants.js → utilities/features/logger/logs/app_logs_constants.js} +1 -1
- package/build/cli/utilities/features/logger/service/logger_service.js +108 -0
- package/build/cli/utilities/features/logger/transports/log_object_map_transport.js +15 -0
- package/build/index.js +14 -2
- package/build/theme/class/archive/theme_archive.js +2 -1
- package/build/theme/class/archive/theme_archive_errors_factory.js +2 -2
- package/build/theme/class/checksums/theme_checksums.js +25 -5
- package/build/theme/class/checksums/theme_checksums_error_factory.js +3 -3
- package/build/theme/class/fetch_resources/fetch_resources.js +34 -4
- package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +1 -1
- package/build/theme/commands/delete/theme_delete_command.js +3 -2
- package/build/theme/commands/info/theme_info_command.js +3 -0
- package/build/theme/commands/init/theme_init_command.js +10 -1
- package/build/theme/commands/list/theme_list_command.js +22 -8
- package/build/theme/commands/publish/theme_publish_command.js +5 -1
- package/build/theme/commands/pull/theme_pull_command.js +17 -5
- package/build/theme/commands/push/theme_push_command.js +7 -1
- package/build/theme/commands/theme_verify_command.js +6 -1
- package/build/theme/commands/ui/theme_error.js +1 -1
- package/build/theme/features/theme/actions/service/theme_actions_service.js +42 -2
- package/build/theme/features/theme/actions/theme_actions_initializer.js +3 -1
- package/build/theme/features/theme/delete/service/theme_delete_service.js +12 -1
- package/build/theme/features/theme/delete/theme_delete_initalizer.js +6 -1
- package/build/theme/features/theme/fetch/service/theme_fetch_service.js +35 -6
- package/build/theme/features/theme/fetch/theme_fetch_initializer.js +3 -0
- package/build/theme/features/theme/init/service/theme_init_service.js +32 -6
- package/build/theme/features/theme/init/theme_init_initializer.js +4 -1
- package/build/theme/features/theme/merge/service/theme_merge_service.js +38 -4
- package/build/theme/features/theme/merge/theme_merge_initializer.js +3 -1
- package/build/theme/features/theme/push/service/theme_push_service.js +38 -10
- package/build/theme/features/theme/push/theme_push_errors_factory.js +2 -2
- package/build/theme/features/theme/push/theme_push_initializer.js +3 -1
- package/build/theme/features/theme/push/theme_push_utils.js +1 -1
- package/build/theme/features/theme/utils/files_structure/theme_file_structure_errors_factory.js +2 -3
- package/build/theme/features/theme/utils/hidden_directory/hidden_directory_utils.js +5 -2
- package/build/theme/features/theme/utils/meta_data/theme_meta_data_error_factory.js +1 -1
- package/build/theme/features/theme/utils/resources/theme_resources_with_id_directory_utils.js +5 -2
- package/build/theme/features/theme/verify/theme_verify_initializer.js +4 -3
- package/build/theme/features/theme/verify/verify/theme_verify_service.js +20 -2
- package/build/theme/features/theme/watch/api/theme_watch_api.js +11 -0
- package/build/theme/features/theme/watch/service/theme_watch_service.js +48 -0
- package/build/theme/features/theme/watch/theme_watch_constants.js +2 -0
- package/build/theme/features/theme/watch/theme_watch_initializer.js +20 -0
- package/build/theme/features/themes/list/services/themes_list_service.js +36 -5
- package/build/theme/features/themes/list/themes_list_initializer.js +3 -1
- package/build/theme/hooks/ensure_theme_meta_data_untouched_hook.js +4 -2
- package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_hook.js +7 -2
- package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +2 -3
- package/build/ui/gradient.js +2 -0
- package/build/ui/hooks/stream_hook.js +26 -0
- package/build/utils/download_file/download_file_errors_factory.js +1 -1
- package/build/utils/download_file/download_file_utils.js +19 -1
- package/build/utils/fs/errors/stream_read_error.js +7 -5
- package/build/utils/fs/errors/stream_write_error.js +7 -5
- package/build/utils/get_api.js +9 -0
- package/build/utils/use_api.js +5 -0
- package/build/utils/zip/create_zip_utils.js +21 -9
- package/build/utils/zip/errors/create_zip_error.js +7 -5
- package/build/utils/zip/errors/open_zip_error.js +7 -5
- package/build/utils/zip/extract_zip_utils.js +90 -15
- package/oclif.config.js +3 -1
- package/package.json +13 -4
- package/build/cli/class/errors/app/app_error.js +0 -17
|
@@ -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 {
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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';
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
|
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/
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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/
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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/
|
|
10
|
+
import { AppError } from '../../../../../cli/utilities/features/logger/logs/app_error.js';
|
|
11
11
|
export class ThemeInitService {
|
|
12
12
|
#httpApi;
|
|
13
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: [
|