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