@shoper/cli 0.5.2-5 → 0.5.2-7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 -21
- 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
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { AsyncFeatureInitializer, FEATURE_CORES_TYPES } from '@dreamcommerce/star_core';
|
|
2
|
+
import { LoggerService } from './service/logger_service.js';
|
|
3
|
+
import { LoggerApi } from './api/logger_api.js';
|
|
4
|
+
import { EXECUTION_CONTEXT_API_NAME, EXECUTION_CONTEXTS } from '../../../features/execution_context/execution_context_constants.js';
|
|
5
|
+
import { LOGGER_DEBUG_MODES, LOGGER_FEATURE_NAME } from './logger_constants.js';
|
|
6
|
+
import { CLI_VERSION_API_NAME } from '../../../features/version/cli_version_constants.js';
|
|
7
|
+
import { join } from '../../../../utils/path_utils.js';
|
|
8
|
+
export class LoggerInitializer extends AsyncFeatureInitializer {
|
|
9
|
+
static featureName = LOGGER_FEATURE_NAME;
|
|
10
|
+
async init() {
|
|
11
|
+
const executionContextApi = this.getApiSync(EXECUTION_CONTEXT_API_NAME);
|
|
12
|
+
const cliVersionApi = this.getApiSync(CLI_VERSION_API_NAME);
|
|
13
|
+
const executionContext = await executionContextApi.getExecutionContext();
|
|
14
|
+
const service = new LoggerService({
|
|
15
|
+
executionContext,
|
|
16
|
+
cliVersion: await cliVersionApi.getGloballyInstalledVersion(),
|
|
17
|
+
debugMode: this._getDebugMode(executionContext.command),
|
|
18
|
+
logFile: this.getLogFilePath(executionContext)
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
cores: [
|
|
22
|
+
{
|
|
23
|
+
type: FEATURE_CORES_TYPES.api,
|
|
24
|
+
instance: new LoggerApi(service)
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
_getDebugMode(command) {
|
|
30
|
+
if (command.includes('--vv'))
|
|
31
|
+
return LOGGER_DEBUG_MODES.detailed;
|
|
32
|
+
if (command.includes('--v'))
|
|
33
|
+
return LOGGER_DEBUG_MODES.standard;
|
|
34
|
+
return LOGGER_DEBUG_MODES.none;
|
|
35
|
+
}
|
|
36
|
+
getLogFilePath(executionContext) {
|
|
37
|
+
const logFileName = 'shoper_cli_debug_log.json';
|
|
38
|
+
if (executionContext.command.includes('--log-file')) {
|
|
39
|
+
return executionContext.type === EXECUTION_CONTEXTS.theme
|
|
40
|
+
? join(executionContext.themeRootDir, logFileName)
|
|
41
|
+
: join(process.cwd(), logFileName);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { AppLog } from './app_log.js';
|
|
2
|
+
import { APP_LOGS_TYPES } from './app_logs_constants.js';
|
|
3
|
+
export class AppError extends AppLog {
|
|
4
|
+
constructor({ details, message, level = APP_LOGS_TYPES.error, tags, error, code }) {
|
|
5
|
+
super({ message, level, tags, details });
|
|
6
|
+
this.tags = {
|
|
7
|
+
...tags,
|
|
8
|
+
code
|
|
9
|
+
};
|
|
10
|
+
this.level = level;
|
|
11
|
+
if (error?.stack)
|
|
12
|
+
this.stacktrace = error.stack;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export class AppLog {
|
|
2
|
+
level;
|
|
3
|
+
message;
|
|
4
|
+
user;
|
|
5
|
+
/**
|
|
6
|
+
* Example:
|
|
7
|
+
* {
|
|
8
|
+
* userId: 123,
|
|
9
|
+
* shopId: 456,
|
|
10
|
+
* }
|
|
11
|
+
*/
|
|
12
|
+
stacktrace;
|
|
13
|
+
// jakie wartosci dopuszczamy w value tagu?
|
|
14
|
+
tags;
|
|
15
|
+
/**
|
|
16
|
+
* Example:
|
|
17
|
+
* {
|
|
18
|
+
* // always added tags:
|
|
19
|
+
* environment: 'MacOS',
|
|
20
|
+
* appVersion: '1.0.0',
|
|
21
|
+
* nodeVersion: 'v16.0.0',
|
|
22
|
+
* traceId: 'unique-trace-id',
|
|
23
|
+
* command: 'theme init 2'
|
|
24
|
+
* // other tags not always added, spefic to the log, EXAMPLE ONLY added quickly:
|
|
25
|
+
* errorCode: 'E_THEME_NOT_FOUND',
|
|
26
|
+
* filePath: '/path/to/file',
|
|
27
|
+
* responseTimeMs: 250,
|
|
28
|
+
* }
|
|
29
|
+
*/
|
|
30
|
+
details;
|
|
31
|
+
// user timestamp in ISO format or server timestamp added when proxied to elastic?
|
|
32
|
+
timestamp = new Date().toISOString();
|
|
33
|
+
constructor({ details, message, level, tags, stacktrace }) {
|
|
34
|
+
this.details = details;
|
|
35
|
+
this.message = message;
|
|
36
|
+
this.level = level;
|
|
37
|
+
this.tags = tags;
|
|
38
|
+
this.stacktrace = stacktrace;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import { v4 as uuid } from 'uuid';
|
|
4
|
+
import { LOGGER_DEBUG_MODES } from '../logger_constants.js';
|
|
5
|
+
export class LoggerService {
|
|
6
|
+
#logger;
|
|
7
|
+
#transport;
|
|
8
|
+
#traceId = uuid();
|
|
9
|
+
#executionContext;
|
|
10
|
+
#cliVersion;
|
|
11
|
+
constructor({ executionContext, cliVersion, debugMode, logFile }) {
|
|
12
|
+
this.#executionContext = executionContext;
|
|
13
|
+
this.#cliVersion = cliVersion;
|
|
14
|
+
const { logger, transport } = this._getLoggerInstance(debugMode, logFile);
|
|
15
|
+
this.#logger = logger;
|
|
16
|
+
this.#transport = transport;
|
|
17
|
+
}
|
|
18
|
+
_getLoggerInstance(debugMode, logFile) {
|
|
19
|
+
const targets = [];
|
|
20
|
+
if (logFile) {
|
|
21
|
+
targets.push({
|
|
22
|
+
target: 'pino/file',
|
|
23
|
+
level: 'debug',
|
|
24
|
+
options: {
|
|
25
|
+
destination: logFile,
|
|
26
|
+
mkdir: true,
|
|
27
|
+
append: false
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
const prettyTransport = {
|
|
32
|
+
target: 'pino-pretty',
|
|
33
|
+
options: {
|
|
34
|
+
messageKey: 'message',
|
|
35
|
+
colorize: true,
|
|
36
|
+
translateTime: 'SYS:standard',
|
|
37
|
+
ignore: debugMode === LOGGER_DEBUG_MODES.standard
|
|
38
|
+
? 'pid,hostname,message,traceId,cliVersion,nodeVersion,environment,command,details'
|
|
39
|
+
: ''
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
/*
|
|
43
|
+
* To bd potem zastąpine customowym transportem który wysyła logi do backendu
|
|
44
|
+
*/
|
|
45
|
+
// const logObjectMapTransport = {
|
|
46
|
+
// target: '../transports/log_object_map_transport.js',
|
|
47
|
+
// options: {
|
|
48
|
+
// traceId: this.#traceId
|
|
49
|
+
// }
|
|
50
|
+
// };
|
|
51
|
+
// TODO docelowo logObjectMapTransport bd wysyłał logi do serwera jezeli bedzie gdzies error a apce
|
|
52
|
+
// targets: debugMode !== LOGGER_DEBUG_MODES.none ? [prettyTransport, logObjectMapTransport] : [logObjectMapTransport]
|
|
53
|
+
if (debugMode !== LOGGER_DEBUG_MODES.none) {
|
|
54
|
+
targets.push(prettyTransport);
|
|
55
|
+
}
|
|
56
|
+
const transport = targets.length
|
|
57
|
+
? pino.transport({
|
|
58
|
+
targets
|
|
59
|
+
})
|
|
60
|
+
: undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Przy dodawaniu logowania na backend trzeba to usunac
|
|
63
|
+
*/
|
|
64
|
+
if (!transport)
|
|
65
|
+
return {};
|
|
66
|
+
const logger = pino({
|
|
67
|
+
level: 'debug',
|
|
68
|
+
base: {
|
|
69
|
+
pid: process.pid,
|
|
70
|
+
hostname: os.hostname(),
|
|
71
|
+
cliVersion: this.#cliVersion,
|
|
72
|
+
nodeVersion: process.version,
|
|
73
|
+
environment: os.type(),
|
|
74
|
+
command: this.#executionContext.command.slice(2).join(' '),
|
|
75
|
+
traceId: this.#traceId
|
|
76
|
+
},
|
|
77
|
+
timestamp: pino.stdTimeFunctions.isoTime,
|
|
78
|
+
messageKey: 'message'
|
|
79
|
+
}, transport);
|
|
80
|
+
return { logger, transport };
|
|
81
|
+
}
|
|
82
|
+
debug(message, props) {
|
|
83
|
+
this.#logger?.debug(props || {}, message);
|
|
84
|
+
}
|
|
85
|
+
info(message, props) {
|
|
86
|
+
this.#logger?.info(props || {}, message);
|
|
87
|
+
}
|
|
88
|
+
warn(message, props) {
|
|
89
|
+
this.#logger?.warn(props || {}, message);
|
|
90
|
+
}
|
|
91
|
+
error(message, props) {
|
|
92
|
+
this.#logger?.error(props || {}, message);
|
|
93
|
+
}
|
|
94
|
+
fatal(message, props) {
|
|
95
|
+
this.#logger?.fatal(props || {}, message);
|
|
96
|
+
}
|
|
97
|
+
async flush() {
|
|
98
|
+
if (!this.#transport || this.#transport?.destroyed) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
return new Promise((resolve) => {
|
|
102
|
+
// The 'close' event is emitted when the stream has been fully closed.
|
|
103
|
+
this.#transport?.on('close', resolve);
|
|
104
|
+
this.#logger?.flush(); // Synchronously flush buffered logs
|
|
105
|
+
this.#transport?.end(); // End the stream, which will trigger 'close'
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -1,22 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
// }
|
|
17
|
-
//
|
|
18
|
-
// function mapLog(obj) {
|
|
19
|
-
// //TODO map for backend structure
|
|
20
|
-
// return obj;
|
|
21
|
-
// }
|
|
22
|
-
export {};
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
export default async function (opts) {
|
|
3
|
+
return new Writable({
|
|
4
|
+
objectMode: true,
|
|
5
|
+
write(chunk, enc, cb) {
|
|
6
|
+
const mapped = mapLog(chunk);
|
|
7
|
+
cb();
|
|
8
|
+
return mapped;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
function mapLog(obj) {
|
|
13
|
+
//TODO map for backend structure
|
|
14
|
+
return obj;
|
|
15
|
+
}
|
package/build/index.js
CHANGED
|
@@ -9,6 +9,8 @@ import { CliAuthRemoveTokenCommand } from './cli/commands/auth/cli_auth_remove_t
|
|
|
9
9
|
import { CliAuthSwitchTokenCommand } from './cli/commands/auth/cli_auth_switch_token_command.js';
|
|
10
10
|
import { CliUIDumpCommand } from './cli/commands/cli_ui_dump_command.js';
|
|
11
11
|
import { CliAuthLogoutCommand } from './cli/commands/auth/cli_auth_logout_command.js';
|
|
12
|
+
import { getApiSync } from './utils/get_api.js';
|
|
13
|
+
import { LOGGER_API_NAME } from './cli/utilities/features/logger/logger_constants.js';
|
|
12
14
|
//TODO
|
|
13
15
|
//@ts-ignore
|
|
14
16
|
if (typeof global.crypto !== 'object') {
|
|
@@ -24,12 +26,21 @@ function getRandomValues(array) {
|
|
|
24
26
|
return crypto.webcrypto.getRandomValues(array);
|
|
25
27
|
}
|
|
26
28
|
process.on('uncaughtException', (err) => {
|
|
27
|
-
//TODO handle error
|
|
28
29
|
console.error('Uncaught Exception:', err);
|
|
30
|
+
const loggerApi = getApiSync(LOGGER_API_NAME);
|
|
31
|
+
if (loggerApi)
|
|
32
|
+
loggerApi.fatal('Uncaught Exception', { error: err });
|
|
29
33
|
process.exit(1);
|
|
30
34
|
});
|
|
31
|
-
process.on('unhandledRejection', (reason
|
|
35
|
+
process.on('unhandledRejection', (reason) => {
|
|
32
36
|
console.error('Unhandled Rejection:', reason);
|
|
37
|
+
const loggerApi = getApiSync(LOGGER_API_NAME);
|
|
38
|
+
if (loggerApi)
|
|
39
|
+
loggerApi.fatal('Unhandled Rejection', {
|
|
40
|
+
details: {
|
|
41
|
+
reason
|
|
42
|
+
}
|
|
43
|
+
});
|
|
33
44
|
process.exit(1);
|
|
34
45
|
});
|
|
35
46
|
const signals = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import globs from 'fast-glob';
|
|
2
|
+
import { createZip } from '../../../utils/zip/create_zip_utils.js';
|
|
3
|
+
import { ThemeFilesStructureUtils } from '../../features/theme/utils/files_structure/theme_files_structure_utils.js';
|
|
4
|
+
import { extname, join } from '../../../utils/path_utils.js';
|
|
5
|
+
import { formatJSONFile } from '../../../utils/fs/fs_utils.js';
|
|
6
|
+
import { ThemeArchiveErrorsFactory } from './theme_archive_errors_factory.js';
|
|
7
|
+
import { ThemeFileStructureErrorsFactory } from '../../features/theme/utils/files_structure/theme_file_structure_errors_factory.js';
|
|
8
|
+
import { ThemeActionsUtils } from '../../features/theme/actions/theme_actions_utils.js';
|
|
9
|
+
export class ThemeArchive {
|
|
10
|
+
#themeRootDir;
|
|
11
|
+
constructor(themeRootDir) {
|
|
12
|
+
this.#themeRootDir = themeRootDir;
|
|
13
|
+
}
|
|
14
|
+
async createFullArchive({ dist, actionValue, actionType, logger }) {
|
|
15
|
+
const filesStructure = await ThemeFilesStructureUtils.getThemeFilesStructure(this.#themeRootDir);
|
|
16
|
+
if (!filesStructure)
|
|
17
|
+
throw ThemeFileStructureErrorsFactory.createNoFilesStructureError();
|
|
18
|
+
try {
|
|
19
|
+
const filesInThemeDirectory = await globs(ThemeActionsUtils.getFilesGlobsThatMatchesActionName({
|
|
20
|
+
actionType,
|
|
21
|
+
actionValue,
|
|
22
|
+
filesStructure
|
|
23
|
+
}), {
|
|
24
|
+
suppressErrors: true,
|
|
25
|
+
onlyFiles: true,
|
|
26
|
+
cwd: this.#themeRootDir
|
|
27
|
+
});
|
|
28
|
+
await this._formatJsonFiles(this.#themeRootDir, filesInThemeDirectory);
|
|
29
|
+
return createZip({
|
|
30
|
+
files: filesInThemeDirectory,
|
|
31
|
+
logger,
|
|
32
|
+
baseDir: this.#themeRootDir,
|
|
33
|
+
dist
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
throw ThemeArchiveErrorsFactory.createErrorWhileCreatingThemeArchive(err);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async _formatJsonFiles(themeRootDir, filesToUpload) {
|
|
41
|
+
await Promise.all(filesToUpload
|
|
42
|
+
.filter((path) => extname(path).toLowerCase() === '.json')
|
|
43
|
+
.map((jsonFile) => formatJSONFile(join(themeRootDir, jsonFile))));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { AppError } from '
|
|
1
|
+
import { AppError } from '../../../cli/utilities/features/logger/logs/app_error.js';
|
|
2
2
|
export class ThemeArchiveErrorsFactory {
|
|
3
3
|
static createErrorWhileCreatingThemeArchive(error) {
|
|
4
4
|
return new AppError({
|
|
5
5
|
code: 'theme_archive.error_creating_archive',
|
|
6
6
|
message: `Error while creating theme archive`,
|
|
7
7
|
level: 'error',
|
|
8
|
-
|
|
8
|
+
error
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
}
|
|
@@ -10,17 +10,18 @@ import { normalize } from 'node:path';
|
|
|
10
10
|
import { ThemePushUtils } from '../../features/theme/push/theme_push_utils.js';
|
|
11
11
|
import { SHOPER_THEME_METADATA_DIR } from '../../constants/directory_contstants.js';
|
|
12
12
|
import { THEME_CURRENT_CHECKSUMS_FILE_NAME, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME, THEME_INITIAL_CHECKSUMS_FILE_NAME, THEME_INITIAL_CHECKSUMS_VERITY_FILE_NAME } from '../../features/theme/theme_constants.js';
|
|
13
|
-
import { FILE_STATES } from '../../../utils/fs/fs_constants.js';
|
|
14
13
|
export class ThemeChecksums {
|
|
15
14
|
#themeDir;
|
|
15
|
+
#loggerApi;
|
|
16
16
|
#currentChecksumsFilePath;
|
|
17
17
|
#currentChecksumsVerificationFilePath;
|
|
18
18
|
#initialChecksumsFilePath;
|
|
19
19
|
#initialChecksumsVerificationFilePath;
|
|
20
20
|
#initialChecksums;
|
|
21
21
|
#currentChecksums;
|
|
22
|
-
constructor(themeDir) {
|
|
22
|
+
constructor({ loggerApi, themeDir }) {
|
|
23
23
|
this.#themeDir = themeDir;
|
|
24
|
+
this.#loggerApi = loggerApi;
|
|
24
25
|
this.#currentChecksumsFilePath = ThemeChecksumsUtils.getCurrentThemeChecksumsFilePath(themeDir);
|
|
25
26
|
this.#currentChecksumsVerificationFilePath = ThemeChecksumsUtils.getCurrentThemeChecksumsVerificationFilePath(themeDir);
|
|
26
27
|
this.#initialChecksumsFilePath = ThemeChecksumsUtils.getInitialThemeChecksumsFilePath(themeDir);
|
|
@@ -32,6 +33,12 @@ export class ThemeChecksums {
|
|
|
32
33
|
this.#initialChecksums = await this._getChecksums(this.#initialChecksumsFilePath);
|
|
33
34
|
return this.#initialChecksums;
|
|
34
35
|
}
|
|
36
|
+
getInitialChecksumsSync() {
|
|
37
|
+
if (this.#initialChecksums)
|
|
38
|
+
return this.#initialChecksums;
|
|
39
|
+
this.#initialChecksums = this._getChecksumsSync(this.#initialChecksumsFilePath);
|
|
40
|
+
return this.#initialChecksums;
|
|
41
|
+
}
|
|
35
42
|
async getCurrentChecksums() {
|
|
36
43
|
if (this.#currentChecksums)
|
|
37
44
|
return this.#currentChecksums;
|
|
@@ -65,22 +72,10 @@ export class ThemeChecksums {
|
|
|
65
72
|
const initialChecksum = await this.getInitialChecksumFromPath(path);
|
|
66
73
|
return !initialChecksum && (await fileExists(join(this.#themeDir, path)));
|
|
67
74
|
}
|
|
68
|
-
async
|
|
69
|
-
const initialChecksum = await this.getInitialChecksumFromPath(path);
|
|
75
|
+
async hasThemeFileBeenModified(path) {
|
|
70
76
|
const currentChecksum = await this.getCurrentChecksumFromPath(path);
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
return FILE_STATES.created;
|
|
74
|
-
}
|
|
75
|
-
else if (initialChecksum && !fileExistsInFs) {
|
|
76
|
-
return FILE_STATES.deleted;
|
|
77
|
-
}
|
|
78
|
-
else if (initialChecksum && currentChecksum && initialChecksum !== currentChecksum) {
|
|
79
|
-
return FILE_STATES.modified;
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
return FILE_STATES.unchanged;
|
|
83
|
-
}
|
|
77
|
+
const initialChecksum = await this.getInitialChecksumFromPath(path);
|
|
78
|
+
return !!currentChecksum && !!initialChecksum && currentChecksum !== initialChecksum;
|
|
84
79
|
}
|
|
85
80
|
async verify() {
|
|
86
81
|
const initialChecksumFilePath = this.#initialChecksumsFilePath;
|
|
@@ -90,6 +85,7 @@ export class ThemeChecksums {
|
|
|
90
85
|
return initialChecksum === initialChecksumVerify;
|
|
91
86
|
}
|
|
92
87
|
async updateAllChecksums() {
|
|
88
|
+
this.#loggerApi?.debug('Updating all checksums.');
|
|
93
89
|
const checksums = await this.computeThemeChecksums();
|
|
94
90
|
return new Promise((resolve, reject) => {
|
|
95
91
|
const currentChecksumFilePath = this.#currentChecksumsFilePath;
|
|
@@ -99,20 +95,24 @@ export class ThemeChecksums {
|
|
|
99
95
|
checksumStream.end();
|
|
100
96
|
checksumStream
|
|
101
97
|
.on('finish', async () => {
|
|
98
|
+
this.#loggerApi?.debug('Finished writing initial checksums file. Creating verification files.');
|
|
102
99
|
const initialChecksumVerifyFilePath = this.#initialChecksumsVerificationFilePath;
|
|
103
100
|
const currentChecksumVerifyFilePath = this.#currentChecksumsVerificationFilePath;
|
|
104
101
|
await this._createThemeChecksumVerifyFile(initialChecksumFilePath, initialChecksumVerifyFilePath);
|
|
105
102
|
await copyFile(initialChecksumFilePath, currentChecksumFilePath);
|
|
106
103
|
await copyFile(initialChecksumVerifyFilePath, currentChecksumVerifyFilePath);
|
|
104
|
+
this.#loggerApi?.debug('All checksums and verification files updated.');
|
|
107
105
|
resolve();
|
|
108
106
|
})
|
|
109
107
|
.on('error', async (err) => {
|
|
108
|
+
this.#loggerApi?.debug('Error writing checksums file. Cleaning up.', { details: { file: initialChecksumFilePath } });
|
|
110
109
|
await removeFile(initialChecksumFilePath, { force: true });
|
|
111
|
-
reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err
|
|
110
|
+
reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err));
|
|
112
111
|
});
|
|
113
112
|
});
|
|
114
113
|
}
|
|
115
114
|
async updateCurrentChecksums() {
|
|
115
|
+
this.#loggerApi?.debug('Updating current checksums.');
|
|
116
116
|
const checksums = await this.computeThemeChecksums();
|
|
117
117
|
return new Promise((resolve, reject) => {
|
|
118
118
|
const currentChecksumFilePath = this.#currentChecksumsFilePath;
|
|
@@ -121,17 +121,23 @@ export class ThemeChecksums {
|
|
|
121
121
|
checksumStream.end();
|
|
122
122
|
checksumStream
|
|
123
123
|
.on('finish', async () => {
|
|
124
|
+
this.#loggerApi?.debug('Finished writing current checksums file. Creating verification file.');
|
|
124
125
|
const currentChecksumVerifyFilePath = this.#currentChecksumsVerificationFilePath;
|
|
125
126
|
await this._createThemeChecksumVerifyFile(currentChecksumFilePath, currentChecksumVerifyFilePath);
|
|
127
|
+
this.#loggerApi?.debug('Current checksums and verification file updated.');
|
|
126
128
|
resolve();
|
|
127
129
|
})
|
|
128
130
|
.on('error', async (err) => {
|
|
131
|
+
this.#loggerApi?.debug('Error writing current checksums file. Cleaning up.', {
|
|
132
|
+
details: { file: currentChecksumFilePath }
|
|
133
|
+
});
|
|
129
134
|
await removeFile(currentChecksumFilePath, { force: true });
|
|
130
|
-
reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err
|
|
135
|
+
reject(ThemeChecksumsErrorFactory.createThemeChecksumError(err));
|
|
131
136
|
});
|
|
132
137
|
});
|
|
133
138
|
}
|
|
134
139
|
async computeThemeChecksums() {
|
|
140
|
+
this.#loggerApi?.debug('Computing theme checksums.');
|
|
135
141
|
const filesToIgnoreInChecksums = [
|
|
136
142
|
join(SHOPER_THEME_METADATA_DIR, THEME_CURRENT_CHECKSUMS_FILE_NAME),
|
|
137
143
|
join(SHOPER_THEME_METADATA_DIR, THEME_CURRENT_CHECKSUMS_VERITY_FILE_NAME),
|
|
@@ -141,40 +147,12 @@ export class ThemeChecksums {
|
|
|
141
147
|
const filesToComputeChecksums = (await ThemePushUtils.getAllFilesThatAreSendToRemote(this.#themeDir))
|
|
142
148
|
.filter((path) => !filesToIgnoreInChecksums.some((ignorePath) => normalize(path) === ignorePath))
|
|
143
149
|
.map((relativePath) => join(this.#themeDir, relativePath));
|
|
150
|
+
this.#loggerApi?.debug('Computing checksums from file structure.', { details: { count: filesToComputeChecksums.length } });
|
|
144
151
|
const { filesChecksumsInDirectories, filesChecksums } = await computeChecksumsFromFilesStructure(filesToComputeChecksums, this.#themeDir);
|
|
145
152
|
const directoriesChecksums = computeDirectoriesChecksums(filesChecksumsInDirectories);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const initialChecksums = await this.getInitialChecksums();
|
|
150
|
-
const currentChecksums = await this.getCurrentChecksums();
|
|
151
|
-
return files.reduce((acc, filePath) => {
|
|
152
|
-
const initialChecksum = initialChecksums[toCurrentPlatformPath(filePath)];
|
|
153
|
-
const currentChecksum = currentChecksums[toCurrentPlatformPath(filePath)];
|
|
154
|
-
if (!initialChecksum) {
|
|
155
|
-
acc.created.push(filePath);
|
|
156
|
-
}
|
|
157
|
-
else if (currentChecksum && initialChecksum !== currentChecksum) {
|
|
158
|
-
acc.modified.push(filePath);
|
|
159
|
-
}
|
|
160
|
-
else if (initialChecksum && !currentChecksum) {
|
|
161
|
-
acc.deleted.push(filePath);
|
|
162
|
-
}
|
|
163
|
-
else {
|
|
164
|
-
acc.unchanged.push(filePath);
|
|
165
|
-
}
|
|
166
|
-
return acc;
|
|
167
|
-
}, {
|
|
168
|
-
created: [],
|
|
169
|
-
modified: [],
|
|
170
|
-
unchanged: [],
|
|
171
|
-
deleted: []
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
async getDeletedFiles() {
|
|
175
|
-
const initialChecksums = await this.getInitialChecksums();
|
|
176
|
-
const currentChecksums = await this.getCurrentChecksums();
|
|
177
|
-
return Object.keys(initialChecksums).filter((filePath) => !currentChecksums[filePath]);
|
|
153
|
+
const allChecksums = { ...filesChecksums, ...directoriesChecksums };
|
|
154
|
+
this.#loggerApi?.debug('Finished computing theme checksums.', { details: { count: Object.keys(allChecksums).length } });
|
|
155
|
+
return allChecksums;
|
|
178
156
|
}
|
|
179
157
|
async _getInitialChecksumsVerification() {
|
|
180
158
|
return await readJSONFile(this.#initialChecksumsVerificationFilePath);
|
|
@@ -195,12 +173,16 @@ export class ThemeChecksums {
|
|
|
195
173
|
return mapKeysPathsToWindowPlatform(checksums);
|
|
196
174
|
}
|
|
197
175
|
async _createThemeChecksumVerifyFile(checksumFilePath, checksumVerifyFullPath) {
|
|
176
|
+
this.#loggerApi?.debug('Creating checksum verification file.', { details: { path: checksumVerifyFullPath } });
|
|
198
177
|
const checksumVerifyStream = createWriteStream(checksumVerifyFullPath);
|
|
199
178
|
const checksumVerify = await computeFileChecksum(checksumFilePath);
|
|
200
179
|
checksumVerifyStream
|
|
201
180
|
.on('error', async (err) => {
|
|
181
|
+
this.#loggerApi?.debug('Error creating checksum verification file. Cleaning up.', {
|
|
182
|
+
details: { file: checksumFilePath }
|
|
183
|
+
});
|
|
202
184
|
await removeFile(checksumFilePath, { force: true });
|
|
203
|
-
throw ThemeChecksumsErrorFactory.createThemeChecksumError(err
|
|
185
|
+
throw ThemeChecksumsErrorFactory.createThemeChecksumError(err);
|
|
204
186
|
})
|
|
205
187
|
.write(JSON.stringify(checksumVerify));
|
|
206
188
|
checksumVerifyStream.end();
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { AppError } from '../../../cli/
|
|
1
|
+
import { AppError } from '../../../cli/utilities/features/logger/logs/app_error.js';
|
|
2
2
|
export class ThemeChecksumsErrorFactory {
|
|
3
|
-
static createThemeChecksumError(
|
|
3
|
+
static createThemeChecksumError(error) {
|
|
4
4
|
return new AppError({
|
|
5
5
|
message: 'Theme checksum error',
|
|
6
6
|
code: 'theme_checksum_error',
|
|
7
|
-
|
|
7
|
+
error
|
|
8
8
|
});
|
|
9
9
|
}
|
|
10
10
|
}
|
|
@@ -12,16 +12,23 @@ import { move } from 'fs-extra';
|
|
|
12
12
|
export class FetchResources {
|
|
13
13
|
#urlsAttempts = {};
|
|
14
14
|
#httpApi;
|
|
15
|
-
|
|
15
|
+
#loggerApi;
|
|
16
|
+
constructor({ httpApi, loggerApi }) {
|
|
16
17
|
this.#httpApi = httpApi;
|
|
18
|
+
this.#loggerApi = loggerApi;
|
|
17
19
|
}
|
|
18
20
|
async fetchResources({ dist, resourcesPart, parts, shopUrl }) {
|
|
21
|
+
this.#loggerApi.debug('Traversing resources part.', { details: { parts } });
|
|
19
22
|
if (Array.isArray(resourcesPart)) {
|
|
20
23
|
for (let i = 0; i < resourcesPart.length; i++) {
|
|
21
24
|
const resource = resourcesPart[i];
|
|
22
25
|
if (isResourceObject(resource)) {
|
|
26
|
+
const resourceUrl = isRelativeUrl(resource.url) ? `${shopUrl}${resource.url}` : resource.url;
|
|
27
|
+
this.#loggerApi.debug('Found resource object. Fetching resource.', {
|
|
28
|
+
details: { url: resourceUrl, parts: [...parts, i] }
|
|
29
|
+
});
|
|
23
30
|
await this._fetchResource({
|
|
24
|
-
url:
|
|
31
|
+
url: resourceUrl,
|
|
25
32
|
dist,
|
|
26
33
|
parts: [...parts, i],
|
|
27
34
|
shopUrl,
|
|
@@ -40,8 +47,12 @@ export class FetchResources {
|
|
|
40
47
|
}
|
|
41
48
|
if (typeof resourcesPart === 'object') {
|
|
42
49
|
if (isResourceObject(resourcesPart)) {
|
|
50
|
+
const resourceUrl = isRelativeUrl(resourcesPart.url) ? `${shopUrl}${resourcesPart.url}` : resourcesPart.url;
|
|
51
|
+
this.#loggerApi.debug('Found resource object. Fetching resource.', {
|
|
52
|
+
details: { url: resourceUrl, parts }
|
|
53
|
+
});
|
|
43
54
|
await this._fetchResource({
|
|
44
|
-
url:
|
|
55
|
+
url: resourceUrl,
|
|
45
56
|
dist,
|
|
46
57
|
parts,
|
|
47
58
|
shopUrl,
|
|
@@ -61,6 +72,7 @@ export class FetchResources {
|
|
|
61
72
|
return;
|
|
62
73
|
}
|
|
63
74
|
async _getResourcesFileContent(resourcePath) {
|
|
75
|
+
this.#loggerApi.debug('Reading and mapping resources file content.', { details: { resourcePath } });
|
|
64
76
|
return mapResourcesToTree(await readJSONFile(resourcePath));
|
|
65
77
|
}
|
|
66
78
|
_getResourcesPart(resources, parts) {
|
|
@@ -68,28 +80,42 @@ export class FetchResources {
|
|
|
68
80
|
}
|
|
69
81
|
async _fetchResource({ url, shopUrl, parts, dist, isPrivate }) {
|
|
70
82
|
this.#urlsAttempts[url] = (this.#urlsAttempts[url] ?? 0) + 1;
|
|
83
|
+
this.#loggerApi.debug('Fetching resource.', {
|
|
84
|
+
details: { url, attempt: this.#urlsAttempts[url], parts, isPrivate }
|
|
85
|
+
});
|
|
71
86
|
if (this.#urlsAttempts[url] > MAX_REQUEST_FOR_RESOURCES)
|
|
72
87
|
throw FetchResourcesErrorsFactory.createErrorFetchingResource(shopUrl, [
|
|
73
88
|
`Failed to fetch ${url} after 3 attempts, for: ${parts.join('')}`
|
|
74
89
|
]);
|
|
75
90
|
const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true, prefix: 'theme_resources_tmp' });
|
|
91
|
+
this.#loggerApi.debug('Created temporary directory for resource fetch.', { details: { tmpDir, url } });
|
|
76
92
|
try {
|
|
93
|
+
this.#loggerApi.debug('Downloading resource file.', { details: { url, dist: tmpDir } });
|
|
77
94
|
const { filename, ext, basename } = await downloadFile({
|
|
78
95
|
dist: tmpDir,
|
|
96
|
+
logger: this.#loggerApi,
|
|
79
97
|
request: this._getRequest({ url, isPrivate }).response
|
|
80
98
|
});
|
|
99
|
+
this.#loggerApi.debug('Resource file downloaded.', { details: { url, filename } });
|
|
81
100
|
if (ext === '.zip') {
|
|
101
|
+
this.#loggerApi.debug('Resource is a zip archive. Extracting.', { details: { source: filename, dist: basename } });
|
|
82
102
|
await extractZip({
|
|
103
|
+
logger: this.#loggerApi,
|
|
83
104
|
source: join(tmpDir, filename),
|
|
84
105
|
dist: join(tmpDir, basename)
|
|
85
106
|
});
|
|
107
|
+
this.#loggerApi.debug('Zip archive extracted.', { details: { filename } });
|
|
86
108
|
if (!(await fileExists(getResourcesPath(join(tmpDir, basename)))))
|
|
87
109
|
return;
|
|
110
|
+
this.#loggerApi.debug('Copying extracted files.', {
|
|
111
|
+
details: { from: join(tmpDir, basename), to: dist }
|
|
112
|
+
});
|
|
88
113
|
await copyFile(join(tmpDir, basename), dist, {
|
|
89
114
|
recursive: true,
|
|
90
115
|
force: true
|
|
91
116
|
});
|
|
92
117
|
const newResources = await this._getResourcesFileContent(getResourcesPath(join(tmpDir, basename)));
|
|
118
|
+
this.#loggerApi.debug('Recursively fetching resources from extracted archive.', { details: { parts } });
|
|
93
119
|
await this.fetchResources({
|
|
94
120
|
dist,
|
|
95
121
|
resourcesPart: this._getResourcesPart(newResources, parts),
|
|
@@ -98,7 +124,11 @@ export class FetchResources {
|
|
|
98
124
|
});
|
|
99
125
|
}
|
|
100
126
|
else {
|
|
101
|
-
|
|
127
|
+
const destinationPath = join(dist, this._getFilepathFromParts(parts), filename);
|
|
128
|
+
this.#loggerApi.debug('Moving downloaded file.', {
|
|
129
|
+
details: { from: join(tmpDir, filename), to: destinationPath }
|
|
130
|
+
});
|
|
131
|
+
await move(join(tmpDir, filename), destinationPath, { overwrite: true });
|
|
102
132
|
}
|
|
103
133
|
}
|
|
104
134
|
catch (err) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AppError } from '../../../cli/
|
|
1
|
+
import { AppError } from '../../../cli/utilities/features/logger/logs/app_error.js';
|
|
2
2
|
export class FetchResourcesErrorsFactory {
|
|
3
3
|
static createErrorFetchingResource(shopUrl, messages) {
|
|
4
4
|
return new AppError({
|