@shoper/cli 0.1.0-7 → 0.1.0-9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/build/cli/auth/api/cli_auth_api.js +15 -2
  2. package/build/cli/auth/cli_auth_constants.js +6 -0
  3. package/build/cli/auth/cli_auth_errors_factory.js +10 -0
  4. package/build/cli/auth/cli_auth_initializer.js +19 -0
  5. package/build/cli/auth/cli_auth_utils.js +22 -0
  6. package/build/cli/auth/model/cli_credentials.js +10 -0
  7. package/build/cli/auth/service/cli_auth_service.js +34 -0
  8. package/build/cli/auth/tokens/api/cli_auth_tokens_api.js +43 -1
  9. package/build/cli/auth/tokens/cli_auth_tokens_constants.js +6 -0
  10. package/build/cli/auth/tokens/cli_auth_tokens_errors_factory.js +10 -0
  11. package/build/cli/auth/tokens/cli_auth_tokens_initalizer.js +35 -1
  12. package/build/cli/auth/tokens/cli_auth_tokens_utils.js +26 -0
  13. package/build/cli/auth/tokens/service/cli_auth_tokens_service.js +84 -4
  14. package/build/cli/auth/tokens/service/cli_auth_tokens_service_constants.js +2 -0
  15. package/build/cli/class/base_cli_command.js +3 -0
  16. package/build/cli/class/errors/app_error/app_error.js +17 -0
  17. package/build/cli/class/errors/app_error/app_error_constants.js +7 -0
  18. package/build/cli/class/errors/file_system_errors_factory.js +26 -0
  19. package/build/cli/class/errors/http_errors_factory.js +21 -0
  20. package/build/cli/cli_constants.js +1 -0
  21. package/build/cli/commands/auth/cli_auth_add_token_command.js +32 -0
  22. package/build/cli/commands/auth/cli_auth_list_tokens_command.js +17 -0
  23. package/build/cli/commands/auth/cli_auth_remove_token_command.js +37 -0
  24. package/build/cli/commands/auth/cli_auth_switch_token_command.js +36 -0
  25. package/build/cli/commands/cli_update_command.js +7 -3
  26. package/build/cli/commands/commands_constants.js +5 -1
  27. package/build/cli/commands/files_diff_command.js +174 -0
  28. package/build/cli/commands/utils/prompt_for_token_utils.js +25 -0
  29. package/build/cli/core/cli_setup.js +20 -7
  30. package/build/cli/features/caches/json_cache/json_cache.js +50 -0
  31. package/build/cli/features/caches/memory_cache.js +6 -0
  32. package/build/cli/features/data_directory/cli_data_directory_constants.js +0 -1
  33. package/build/cli/features/data_directory/cli_data_directory_utils.js +3 -4
  34. package/build/cli/features/data_directory/service/cli_data_directory_service.js +2 -2
  35. package/build/cli/features/execution_context/execution_context_service.js +3 -5
  36. package/build/cli/features/http_requester/http_client.js +32 -1
  37. package/build/cli/features/version/service/cli_version_service.js +2 -4
  38. package/build/cli/hooks/authorization/ensure_authorization_hook.js +11 -6
  39. package/build/cli/hooks/authorization/ensure_authorization_hook_constants.js +8 -1
  40. package/build/index.js +34 -1
  41. package/build/theme/class/fetch_resources/fetch_resources.js +127 -0
  42. package/build/theme/class/fetch_resources/fetch_resources_constants.js +2 -0
  43. package/build/theme/class/fetch_resources/fetch_resources_errors_factory.js +11 -0
  44. package/build/theme/class/fetch_resources/fetch_resources_utils.js +35 -0
  45. package/build/theme/commands/theme_commands_constants.js +8 -0
  46. package/build/theme/commands/theme_init_command.js +53 -0
  47. package/build/theme/commands/theme_list_command.js +16 -0
  48. package/build/theme/commands/theme_pull_command.js +126 -0
  49. package/build/theme/commands/theme_push_command.js +65 -0
  50. package/build/theme/commands/theme_show_changes_command.js +60 -0
  51. package/build/theme/commands/theme_verify_command.js +43 -0
  52. package/build/theme/features/theme/actions/api/theme_actions_api.js +19 -0
  53. package/build/theme/features/theme/actions/service/theme_actions_service.js +92 -0
  54. package/build/theme/features/theme/actions/service/theme_actions_service_constants.js +2 -0
  55. package/build/theme/features/theme/actions/theme_actions_constants.js +15 -0
  56. package/build/theme/features/theme/actions/theme_actions_initializer.js +27 -0
  57. package/build/theme/features/theme/actions/theme_actions_utils.js +8 -0
  58. package/build/theme/features/theme/directory/theme_directory_utils.js +61 -14
  59. package/build/theme/features/theme/fetch/api/theme_fetch_api.js +16 -0
  60. package/build/theme/features/theme/fetch/http/theme_fetch_http_api.js +18 -0
  61. package/build/theme/features/theme/fetch/service/theme_fetch_service.js +113 -0
  62. package/build/theme/features/theme/fetch/theme_fetch_constants.js +7 -0
  63. package/build/theme/features/theme/fetch/theme_fetch_initializer.js +23 -0
  64. package/build/theme/features/theme/init/api/theme_init_api.js +13 -0
  65. package/build/theme/features/theme/init/http/theme_init_http_api.js +18 -0
  66. package/build/theme/features/theme/init/service/theme_init_service.js +28 -0
  67. package/build/theme/features/theme/init/theme_init_constants.js +2 -0
  68. package/build/theme/features/theme/init/theme_init_initializer.js +22 -0
  69. package/build/theme/features/theme/merge/api/theme_merge_api.js +28 -0
  70. package/build/theme/features/theme/merge/service/theme_merge_service.js +56 -0
  71. package/build/theme/features/theme/merge/theme_merge_constants.js +9 -0
  72. package/build/theme/features/theme/merge/theme_merge_initializer.js +18 -0
  73. package/build/theme/features/theme/publish/theme_publish_constants.js +2 -0
  74. package/build/theme/features/theme/publish/theme_publish_utils.js +7 -0
  75. package/build/theme/features/theme/push/api/theme_push_api.js +13 -0
  76. package/build/theme/features/theme/push/http_api/theme_push_http_api.js +21 -0
  77. package/build/theme/features/theme/push/service/theme_push_service.js +200 -0
  78. package/build/theme/features/theme/push/service/theme_push_service_constants.js +1 -0
  79. package/build/theme/features/theme/push/theme_push_constants.js +4 -0
  80. package/build/theme/features/theme/push/theme_push_errors_factory.js +41 -0
  81. package/build/theme/features/theme/push/theme_push_initializer.js +27 -0
  82. package/build/theme/features/theme/theme_constants.js +6 -0
  83. package/build/theme/features/theme/utils/checksums/theme_checksums_error_factory.js +10 -0
  84. package/build/theme/features/theme/utils/checksums/theme_checksums_utils.js +94 -0
  85. package/build/theme/features/theme/utils/directories/theme_resources_with_id_directory_utils.js +80 -0
  86. package/build/theme/features/theme/utils/theme_images_utils.js +30 -0
  87. package/build/theme/features/themes/list/api/themes_list_api.js +13 -0
  88. package/build/theme/features/themes/{http/shoper_themes_http_api.js → list/http/themes_list_http_api.js} +3 -2
  89. package/build/theme/features/themes/{model/theme_metadata.js → list/model/theme_list_metadata.js} +3 -1
  90. package/build/theme/features/themes/list/services/themes_list_service.js +37 -0
  91. package/build/theme/features/themes/list/themes_list_constants.js +2 -0
  92. package/build/theme/features/themes/list/themes_list_initializer.js +20 -0
  93. package/build/theme/hooks/ensure_theme_meta_data_untouched.js +17 -0
  94. package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date.js +21 -0
  95. package/build/theme/hooks/theme_checksums/ensure_theme_current_checksums_up_to_date_constants.js +7 -0
  96. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook.js +45 -0
  97. package/build/theme/hooks/themes_actions/ensure_themes_actions_hook_constants.js +7 -0
  98. package/build/theme/index.js +13 -4
  99. package/build/theme/utils/directory_validator/directory_validator_constants.js +13 -0
  100. package/build/theme/utils/directory_validator/directory_validator_utils.js +185 -0
  101. package/build/utils/checksums/checksums_utils.js +95 -0
  102. package/build/utils/checksums/checksums_utils_constants.js +1 -0
  103. package/build/utils/date_utils.js +3 -0
  104. package/build/utils/download_file/download_file_errors_factory.js +9 -0
  105. package/build/utils/download_file/download_file_utils.js +46 -0
  106. package/build/utils/fs/errors/stream_read_error.js +11 -0
  107. package/build/utils/fs/errors/stream_write_error.js +11 -0
  108. package/build/utils/fs/fs_utils.js +155 -0
  109. package/build/utils/http_utils.js +10 -0
  110. package/build/utils/path_utils.js +37 -0
  111. package/build/utils/stream_transforms/json_indent_transform.js +21 -0
  112. package/build/utils/url_utils.js +9 -0
  113. package/build/utils/zip/create_zip_utils.js +80 -0
  114. package/build/utils/zip/errors/create_zip_error.js +11 -0
  115. package/build/utils/zip/errors/open_zip_error.js +11 -0
  116. package/build/utils/zip/extract_zip_utils.js +104 -0
  117. package/oclif.config.js +4 -2
  118. package/package.json +36 -7
  119. package/build/cli/hooks/migration/migration_hook.js +0 -4
  120. package/build/theme/commands/list_command.js +0 -12
  121. package/build/theme/commands/pull_command.js +0 -24
  122. package/build/theme/features/theme/directory/theme_directories_utils.js +0 -10
  123. package/build/theme/features/theme/pull/api/shoper_theme_pull_api.js +0 -9
  124. package/build/theme/features/theme/pull/http/shoper_theme_pull_http_api.js +0 -14
  125. package/build/theme/features/theme/pull/service/shoper_theme_pull_service.js +0 -68
  126. package/build/theme/features/theme/pull/shoper_theme_pull_initializer.js +0 -22
  127. package/build/theme/features/themes/api/shoper_themes_api.js +0 -14
  128. package/build/theme/features/themes/services/shoper_themes_service.js +0 -15
  129. package/build/theme/features/themes/shoper_themes_constants.js +0 -2
  130. package/build/theme/features/themes/shoper_themes_initalizer.js +0 -20
  131. package/build/utils/fs.js +0 -44
  132. package/build/utils/path.js +0 -13
@@ -0,0 +1,174 @@
1
+ //@ts-nocheck
2
+ import { BaseCliCommand } from '../class/base_cli_command.js';
3
+ import * as readline from 'node:readline/promises';
4
+ import * as fs from 'node:fs';
5
+ import { Args } from '@oclif/core';
6
+ import process from 'node:process';
7
+ import * as path from 'node:path';
8
+ import { diffWords } from 'diff';
9
+ export class CliFilesDiffCommand extends BaseCliCommand {
10
+ static summary = 'Differentiate between two files';
11
+ static args = {
12
+ file1: Args.string({
13
+ name: 'file1',
14
+ required: true,
15
+ description: 'First file to compare',
16
+ type: 'string'
17
+ }),
18
+ file2: Args.string({
19
+ name: 'file2',
20
+ required: true,
21
+ description: 'Second file to compare',
22
+ type: 'string'
23
+ })
24
+ };
25
+ async run() {
26
+ const { args } = await this.parse(CliFilesDiffCommand);
27
+ const inputAPath = args.file1;
28
+ const inputBPath = args.file2;
29
+ return new Promise((resolve, reject) => {
30
+ Promise.all([readLines(inputAPath), readLines(inputBPath)]).then((result) => {
31
+ const [aLines, bLines] = result;
32
+ // console.log('aLines', aLines);
33
+ // console.log('bLines', bLines);
34
+ merge(aLines, bLines);
35
+ resolve();
36
+ });
37
+ // aStream.on('line', (input) => {
38
+ // console.log('aStream line: ', input);
39
+ // });
40
+ //
41
+ // bStream.on('line', (input) => {
42
+ // console.log('bStream line: ', input);
43
+ // });
44
+ });
45
+ }
46
+ }
47
+ const readLines = async (filePath) => {
48
+ return new Promise((resolve, reject) => {
49
+ const lines = [];
50
+ const inputStream = readline.createInterface({
51
+ input: fs.createReadStream(path.resolve(process.cwd(), filePath)),
52
+ crlfDelay: Infinity
53
+ });
54
+ inputStream.on('line', (line) => {
55
+ lines.push(line);
56
+ });
57
+ inputStream.on('close', () => {
58
+ resolve(lines);
59
+ });
60
+ inputStream.on('error', (err) => {
61
+ reject(err);
62
+ });
63
+ });
64
+ };
65
+ const merge = (aLines, bLines) => {
66
+ let hasConflict = false;
67
+ const maxLength = Math.max(aLines.length, bLines.length);
68
+ const outputPath = path.resolve(process.cwd(), 'merge.txt');
69
+ const outStream = fs.createWriteStream(outputPath, { encoding: 'utf8' });
70
+ for (let i = 0; i < maxLength; i++) {
71
+ const a = aLines[i] ?? '';
72
+ const b = bLines[i] ?? '';
73
+ if (a === b) {
74
+ outStream.write(a + '\n');
75
+ }
76
+ else {
77
+ hasConflict = true;
78
+ console.log('⚠️ Conflict detected:');
79
+ console.log('a:', a);
80
+ console.log('b:', b);
81
+ const { aFormatted, bFormatted } = formatWordDiff(a, b);
82
+ console.log('aFormatted', aFormatted);
83
+ console.log('bFormatted', bFormatted);
84
+ outStream.write('<<<<<<< mine\n');
85
+ outStream.write(aFormatted + '\n');
86
+ outStream.write('=======\n');
87
+ outStream.write(bFormatted + '\n');
88
+ outStream.write('>>>>>>> theirs\n');
89
+ }
90
+ }
91
+ outStream.end();
92
+ outStream.on('finish', () => {
93
+ if (hasConflict) {
94
+ console.log('⚠️ Conflicts detected. Check', outputPath);
95
+ }
96
+ else {
97
+ console.log('✅ Merged with no conflicts. Output written to', outputPath);
98
+ }
99
+ });
100
+ };
101
+ function formatWordDiff(aLine, bLine) {
102
+ const changes = diffWords(aLine, bLine);
103
+ const aFormatted = changes.map((part) => (part.added ? '' : part.value)).join('');
104
+ const bFormatted = changes.map((part) => (part.removed ? '' : part.value)).join('');
105
+ return {
106
+ aFormatted: aFormatted.trimEnd(),
107
+ bFormatted: bFormatted.trimEnd()
108
+ };
109
+ }
110
+ // const fs = require('fs');
111
+ // const path = require('path');
112
+ // const readline = require('readline');
113
+ // const Diff = require('diff');
114
+ //
115
+ // async function mergeWithCommentsStream(fileAPath, fileBPath, outputPath) {
116
+ // const textA = await fs.promises.readFile(fileAPath, 'utf8');
117
+ // const textB = await fs.promises.readFile(fileBPath, 'utf8');
118
+ //
119
+ // const diffs = Diff.diffLines(textA, textB);
120
+ // const outputStream = fs.createWriteStream(outputPath, { encoding: 'utf8' });
121
+ //
122
+ // let currentState = 'equal'; // 'equal' | 'added' | 'removed'
123
+ //
124
+ // for (const part of diffs) {
125
+ // const lines = part.value.endsWith('\n') ? part.value.slice(0, -1).split('\n') : part.value.split('\n');
126
+ //
127
+ // if (part.added) {
128
+ // if (currentState !== 'added') {
129
+ // outputStream.write('added >>>>>\n');
130
+ // currentState = 'added';
131
+ // }
132
+ // for (const line of lines) {
133
+ // outputStream.write(line + '\n');
134
+ // }
135
+ // } else if (part.removed) {
136
+ // if (currentState !== 'removed') {
137
+ // outputStream.write('removed >>>>>\n');
138
+ // currentState = 'removed';
139
+ // }
140
+ // for (const line of lines) {
141
+ // outputStream.write(line + '\n');
142
+ // }
143
+ // } else {
144
+ // // Close any previous block
145
+ // if (currentState === 'added') {
146
+ // outputStream.write('end-added >>>\n');
147
+ // } else if (currentState === 'removed') {
148
+ // outputStream.write('end-removed >>>\n');
149
+ // }
150
+ // currentState = 'equal';
151
+ //
152
+ // for (const line of lines) {
153
+ // outputStream.write(line + '\n');
154
+ // }
155
+ // }
156
+ // }
157
+ //
158
+ // // Final cleanup in case the last block was added/removed
159
+ // if (currentState === 'added') {
160
+ // outputStream.write('end-added >>>\n');
161
+ // } else if (currentState === 'removed') {
162
+ // outputStream.write('end-removed >>>\n');
163
+ // }
164
+ //
165
+ // outputStream.end();
166
+ // console.log(`✅ Merge complete. Output written to: ${outputPath}`);
167
+ // }
168
+ //
169
+ // // Example usage
170
+ // const fileA = path.resolve('versionA.txt');
171
+ // const fileB = path.resolve('versionB.txt');
172
+ // const outputFile = path.resolve('mergedWithComments.txt');
173
+ //
174
+ // mergeWithCommentsStream(fileA, fileB, outputFile);
@@ -0,0 +1,25 @@
1
+ import { CLiAuthTokensUtils } from '../../auth/tokens/cli_auth_tokens_utils.js';
2
+ import inquirer from 'inquirer';
3
+ export const promptForToken = async (cliAuthTokensApi) => {
4
+ try {
5
+ const { token } = await inquirer.prompt([
6
+ {
7
+ type: 'input',
8
+ name: 'token',
9
+ required: true,
10
+ message: 'Enter token: '
11
+ }
12
+ ]);
13
+ if (CLiAuthTokensUtils.hasTokenExpired(token)) {
14
+ console.log('Token is expired');
15
+ return;
16
+ }
17
+ cliAuthTokensApi.addToken(token);
18
+ cliAuthTokensApi.setDefaultToken(cliAuthTokensApi.getTokensCount());
19
+ console.log('Token added successfully');
20
+ }
21
+ catch (err) {
22
+ console.error(err);
23
+ process.exit(1);
24
+ }
25
+ };
@@ -1,31 +1,44 @@
1
- import { getOSRootDirectory } from '../../utils/fs.js';
1
+ import { getOSRootDirectory } from '../../utils/fs/fs_utils.js';
2
2
  import * as process from 'process';
3
3
  import tmp from 'tmp-promise';
4
- import { SanitizerInitializer, StarCoreSetup } from '@dreamcommerce/star_core';
5
4
  import { HTTPRequesterInitializer } from '../features/http_requester/http_requester_initializer.js';
6
- import { ShoperThemesInitializer } from '../../theme/features/themes/shoper_themes_initalizer.js';
5
+ import { SanitizerInitializer, StarCoreSetup } from '@dreamcommerce/star_core';
6
+ import { CliDataDirectoryInitializer } from '../features/data_directory/cli_data_directory_initializer.js';
7
7
  import { ExecutionContextInitializer } from '../features/execution_context/execution_context_initalizer.js';
8
8
  import { CliVersionInitializer } from '../features/version/cli_version_initializer.js';
9
- import { CliDataDirectoryInitializer } from '../features/data_directory/cli_data_directory_initializer.js';
9
+ import { CliAuthTokensInitializer } from '../auth/tokens/cli_auth_tokens_initalizer.js';
10
+ import { CliAuthInitializer } from '../auth/cli_auth_initializer.js';
11
+ import { ThemesListInitializer } from '../../theme/features/themes/list/themes_list_initializer.js';
12
+ import { ThemeInitInitializer } from '../../theme/features/theme/init/theme_init_initializer.js';
13
+ import { ThemeFetchInitializer } from '../../theme/features/theme/fetch/theme_fetch_initializer.js';
14
+ import { ThemeMergeInitializer } from '../../theme/features/theme/merge/theme_merge_initializer.js';
15
+ import { ThemeActionsInitializer } from '../../theme/features/theme/actions/theme_actions_initializer.js';
16
+ import { ThemePushInitializer } from '../../theme/features/theme/push/theme_push_initializer.js';
10
17
  tmp.setGracefulCleanup();
11
18
  export const cliSetup = async () => {
12
19
  //TODO jakis ładny komuniakt błedu
13
20
  if (process.cwd() === getOSRootDirectory())
14
21
  throw 'You cannot run this command in the root directory of the os system';
15
22
  await StarCoreSetup.setup({
16
- //TODO dnamicznie inicjalizowanie ficzurów wykorzystywanych w poszczególnych komendach
17
23
  features: [
18
24
  SanitizerInitializer,
19
25
  HTTPRequesterInitializer,
20
26
  CliDataDirectoryInitializer,
21
27
  ExecutionContextInitializer,
22
28
  CliVersionInitializer,
23
- ShoperThemesInitializer
29
+ CliAuthTokensInitializer,
30
+ CliAuthInitializer,
31
+ ThemesListInitializer,
32
+ ThemeActionsInitializer,
33
+ //TODO dnamicznie inicjalizowanie ficzurów wykorzystywanych w poszczególnych komendach
34
+ ThemeInitInitializer,
35
+ ThemeMergeInitializer,
36
+ ThemeFetchInitializer,
37
+ ThemePushInitializer
24
38
  ],
25
39
  options: {
26
40
  featuresTracking: false,
27
41
  messageQueue: false
28
42
  }
29
43
  });
30
- //TODO structure validation
31
44
  };
@@ -0,0 +1,50 @@
1
+ import { FeatureCore } from '@dreamcommerce/star_core';
2
+ import Conf from 'conf';
3
+ export class JsonCache extends FeatureCore {
4
+ #cache;
5
+ moduleName = 'JsonCache';
6
+ constructor({ path, name, configFileMode = 600, ...rest }) {
7
+ super();
8
+ this.#cache = new Conf({
9
+ cwd: path,
10
+ configName: name,
11
+ configFileMode,
12
+ ...rest
13
+ });
14
+ }
15
+ set(key, value) {
16
+ this.#cache.set(key, value);
17
+ }
18
+ get(key) {
19
+ return this.#cache.get(key) ?? null;
20
+ }
21
+ getAll() {
22
+ return Object.keys(this.#cache.store).map((key) => this.get(key));
23
+ }
24
+ getKeys() {
25
+ return Object.keys(this.#cache.store);
26
+ }
27
+ remove(key) {
28
+ this.#cache.delete(key);
29
+ }
30
+ clear() {
31
+ this.#cache.clear();
32
+ }
33
+ has(key) {
34
+ return this.#cache.has(key);
35
+ }
36
+ get size() {
37
+ return this.#cache.size;
38
+ }
39
+ getMultiple(keys) {
40
+ return keys.map((key) => this.get(key)).filter(Boolean);
41
+ }
42
+ setMultiple(storeRecord) {
43
+ storeRecord.forEach(({ key, value }) => {
44
+ this.set(key, value);
45
+ });
46
+ }
47
+ removeMultiple(keys) {
48
+ keys.forEach((key) => this.remove(key));
49
+ }
50
+ }
@@ -14,6 +14,12 @@ export class MemoryCache extends FeatureCore {
14
14
  get(key) {
15
15
  return this.#cache.get(key) ?? null;
16
16
  }
17
+ getAll() {
18
+ return Array.from(this.#cache.values());
19
+ }
20
+ getKeys() {
21
+ return Array.from(this.#cache.keys());
22
+ }
17
23
  remove(key) {
18
24
  this.#cache.delete(key);
19
25
  }
@@ -1,4 +1,3 @@
1
1
  export const CLI_DATA_DIRECTORY_API_NAME = 'CliDataDirectoryApi';
2
2
  export const CLI_DATA_DIRECTORY_FEATURE_NAME = 'CliDataDirectory';
3
3
  export const SHOPER_CLI_DATA_DIRECTORY = '.shoper-cli';
4
- export const SHOPER_CLI_CACHE_DIRECTORY = '.cache';
@@ -1,11 +1,10 @@
1
- import { directoryExists, makeDirectory } from '../../../utils/fs.js';
2
- import { join } from '../../../utils/path.js';
3
- import { SHOPER_CLI_CACHE_DIRECTORY, SHOPER_CLI_DATA_DIRECTORY } from './cli_data_directory_constants.js';
1
+ import { directoryExists, makeDirectory } from '../../../utils/fs/fs_utils.js';
2
+ import { join } from '../../../utils/path_utils.js';
3
+ import { SHOPER_CLI_DATA_DIRECTORY } from './cli_data_directory_constants.js';
4
4
  export class CliDataDirectoryUtils {
5
5
  static async createDataDirectory(path) {
6
6
  try {
7
7
  await makeDirectory(join(path, SHOPER_CLI_DATA_DIRECTORY));
8
- await makeDirectory(join(path, SHOPER_CLI_DATA_DIRECTORY, SHOPER_CLI_CACHE_DIRECTORY));
9
8
  }
10
9
  catch (e) {
11
10
  // TODO handle error
@@ -1,6 +1,6 @@
1
- import * as os from 'os';
1
+ import * as os from 'node:os';
2
2
  import { CliDataDirectoryUtils } from '../cli_data_directory_utils.js';
3
- import { join } from '../../../../utils/path.js';
3
+ import { join } from '../../../../utils/path_utils.js';
4
4
  import { SHOPER_CLI_DATA_DIRECTORY } from '../cli_data_directory_constants.js';
5
5
  export class CliDataDirectoryService {
6
6
  #dataDirectoryPath = os.homedir();
@@ -1,4 +1,4 @@
1
- import process from 'process';
1
+ import process from 'node:process';
2
2
  import { EXECUTION_CONTEXTS } from './execution_context_constants.js';
3
3
  import { ThemeDirectoryUtils } from '../../../theme/features/theme/directory/theme_directory_utils.js';
4
4
  export class ExecutionContextService {
@@ -11,9 +11,7 @@ export class ExecutionContextService {
11
11
  }
12
12
  async _getGlobalExecutionContext() {
13
13
  return {
14
- type: EXECUTION_CONTEXTS.global,
15
- //TODO get available themes within process.cwd()
16
- availableThemes: []
14
+ type: EXECUTION_CONTEXTS.global
17
15
  };
18
16
  }
19
17
  async getExecutionContext() {
@@ -31,7 +29,7 @@ export class ExecutionContextService {
31
29
  type: EXECUTION_CONTEXTS.theme,
32
30
  themeId: themeDirectoryMetadata.themeId,
33
31
  executionDir: process.cwd(),
34
- themRootDir: themeRoot
32
+ themeRootDir: themeRoot
35
33
  };
36
34
  }
37
35
  }
@@ -1,8 +1,39 @@
1
1
  import axios from 'axios';
2
- export class HttpClient {
2
+ import { FeatureCore } from '@dreamcommerce/star_core';
3
+ import { CLI_AUTH_API_NAME } from '../../auth/cli_auth_constants.js';
4
+ import { CLI_AUTH_TOKENS_API_NAME } from '../../auth/tokens/cli_auth_tokens_constants.js';
5
+ export class HttpClient extends FeatureCore {
3
6
  #axios;
4
7
  constructor() {
8
+ super();
5
9
  this.#axios = axios;
10
+ this._setupMiddlewares();
11
+ }
12
+ _setupMiddlewares() {
13
+ this.#axios.interceptors.request.use((config) => {
14
+ if (config.isPrivate) {
15
+ const accessToken = this._getAccessToken();
16
+ if (!accessToken)
17
+ throw Error('Unauthorized');
18
+ config.headers['Authorization'] = `Bearer ${accessToken}`;
19
+ }
20
+ return config;
21
+ }, (error) => {
22
+ return Promise.reject(error);
23
+ });
24
+ this.#axios.interceptors.response.use((response) => {
25
+ return response;
26
+ }, (error) => {
27
+ return Promise.reject(error);
28
+ });
29
+ }
30
+ _getAccessToken() {
31
+ const credentialsApi = this.getApiSync(CLI_AUTH_API_NAME);
32
+ const credentials = credentialsApi.getCredentials();
33
+ if (!credentials)
34
+ return null;
35
+ const cliAuthTokensApi = this.getApiSync(CLI_AUTH_TOKENS_API_NAME);
36
+ return cliAuthTokensApi.getDefaultToken();
6
37
  }
7
38
  fetch(options) {
8
39
  const axiosOptions = {
@@ -1,13 +1,11 @@
1
1
  import { exec } from 'child_process';
2
2
  import { CLI_NAME } from '../../../cli_constants.js';
3
- //TODO clean cache command
4
3
  export class CliVersionService {
5
4
  async update() {
6
- return new Promise((resolve) => {
5
+ return new Promise((resolve, reject) => {
7
6
  exec(`npm update -g ${CLI_NAME}`, (error, stdout) => {
8
- //TODO error
9
7
  if (error)
10
- throw new Error(Error.name);
8
+ reject(error);
11
9
  resolve(stdout);
12
10
  });
13
11
  });
@@ -1,11 +1,16 @@
1
1
  import { COMMANDS_THAT_NOT_REQUIRE_AUTHORIZATION } from './ensure_authorization_hook_constants.js';
2
+ import { useApi } from '../ensure_cli_initialized_hook.js';
3
+ import { CLI_AUTH_API_NAME } from '../../auth/cli_auth_constants.js';
4
+ import { CLI_AUTH_TOKENS_API_NAME } from '../../auth/tokens/cli_auth_tokens_constants.js';
5
+ import { promptForToken } from '../../commands/utils/prompt_for_token_utils.js';
6
+ import { CliAuthUtils } from '../../auth/cli_auth_utils.js';
2
7
  const ensureAuthorizationHook = async ({ Command }) => {
3
- const isAuthorized = true;
4
- if (isAuthorized || COMMANDS_THAT_NOT_REQUIRE_AUTHORIZATION.includes(Command.id))
8
+ if (COMMANDS_THAT_NOT_REQUIRE_AUTHORIZATION.includes(Command.id))
5
9
  return;
6
- // Allow logs or cleanup to flush
7
- await new Promise((resolve) => setTimeout(resolve, 10));
8
- // Forcefully exit
9
- process.exit(1);
10
+ const cliAuthApi = useApi(CLI_AUTH_API_NAME);
11
+ const cliAuthTokensApi = useApi(CLI_AUTH_TOKENS_API_NAME);
12
+ while (!CliAuthUtils.checkCredentials(cliAuthApi, Command)) {
13
+ await promptForToken(cliAuthTokensApi);
14
+ }
10
15
  };
11
16
  export default ensureAuthorizationHook;
@@ -1,2 +1,9 @@
1
1
  import { CLI_COMMANDS_NAMES } from '../../commands/commands_constants.js';
2
- export const COMMANDS_THAT_NOT_REQUIRE_AUTHORIZATION = [CLI_COMMANDS_NAMES.update, CLI_COMMANDS_NAMES.update];
2
+ export const COMMANDS_THAT_NOT_REQUIRE_AUTHORIZATION = [
3
+ CLI_COMMANDS_NAMES.update,
4
+ CLI_COMMANDS_NAMES.update,
5
+ CLI_COMMANDS_NAMES.authAddToken,
6
+ CLI_COMMANDS_NAMES.authRemoveToken,
7
+ CLI_COMMANDS_NAMES.authListTokens,
8
+ CLI_COMMANDS_NAMES.switchToken
9
+ ];
package/build/index.js CHANGED
@@ -3,6 +3,10 @@ import { COMMANDS as THEME_COMMANDS } from './theme/index.js';
3
3
  import crypto from 'crypto';
4
4
  import { CLI_COMMANDS_NAMES } from './cli/commands/commands_constants.js';
5
5
  import { CliUpdateCommand } from './cli/commands/cli_update_command.js';
6
+ import { CliAuthListTokensCommand } from './cli/commands/auth/cli_auth_list_tokens_command.js';
7
+ import { CliAuthAddTokenCommand } from './cli/commands/auth/cli_auth_add_token_command.js';
8
+ import { CliAuthRemoveTokenCommand } from './cli/commands/auth/cli_auth_remove_token_command.js';
9
+ import { CliAuthSwitchTokenCommand } from './cli/commands/auth/cli_auth_switch_token_command.js';
6
10
  //TODO
7
11
  //@ts-ignore
8
12
  if (typeof global.crypto !== 'object') {
@@ -19,7 +23,11 @@ function getRandomValues(array) {
19
23
  }
20
24
  process.on('uncaughtException', (err) => {
21
25
  //TODO handle error
22
- console.log('err', err);
26
+ console.error('Uncaught Exception:', err);
27
+ process.exit(1);
28
+ });
29
+ process.on('unhandledRejection', (reason, promise) => {
30
+ console.error('Unhandled Rejection:', reason);
23
31
  process.exit(1);
24
32
  });
25
33
  const signals = ['SIGINT', 'SIGTERM', 'SIGQUIT'];
@@ -30,6 +38,31 @@ signals.forEach((signal) => {
30
38
  });
31
39
  export const COMMANDS = {
32
40
  [CLI_COMMANDS_NAMES.update]: CliUpdateCommand,
41
+ [CLI_COMMANDS_NAMES.authListTokens]: CliAuthListTokensCommand,
42
+ [CLI_COMMANDS_NAMES.authAddToken]: CliAuthAddTokenCommand,
43
+ [CLI_COMMANDS_NAMES.authRemoveToken]: CliAuthRemoveTokenCommand,
44
+ [CLI_COMMANDS_NAMES.switchToken]: CliAuthSwitchTokenCommand,
33
45
  ...THEME_COMMANDS
34
46
  };
35
47
  export { runCLI } from './cli/index.js';
48
+ /**
49
+ * TODO:
50
+ * testy verify
51
+ * - usuniecie po koleji .shoper, macros, modules, settings, styles...
52
+ * testy theme show-changes
53
+ * - macro
54
+ * - dodawanie, zmienianie i usuwanie makr
55
+ * testy theme verify
56
+ * - makro
57
+ * - dodawanie, zmienianie i usuwanie makr
58
+ * testy pull push
59
+ * - nie skinstore
60
+ * - push nowego modułu, podmieni sie folder i checksumy przywróćenie foledu bez checksum i push error z permissions
61
+ * - dodawanie, modzenie i usuwanie customowych makr
62
+ * - modzenie makr
63
+ * - dodawanie i usuwanie customowych modułów
64
+ * - podmiana thumbnail
65
+ * - skinstore
66
+ * - modzenie danych settingsów skinstore
67
+ * - dodawanie, usuwanie, podmienianie obrazków
68
+ */
@@ -0,0 +1,127 @@
1
+ import { REQUEST_TYPES } from '@dreamcommerce/star_core';
2
+ import { downloadFile } from '../../../utils/download_file/download_file_utils.js';
3
+ import { extractZip } from '../../../utils/zip/extract_zip_utils.js';
4
+ import { join } from '../../../utils/path_utils.js';
5
+ import tmp from 'tmp-promise';
6
+ import { copyFile, fileExists, readJSONFile } from '../../../utils/fs/fs_utils.js';
7
+ import { getResourcesPath, isResourceObject, mapResourcesToTree } from './fetch_resources_utils.js';
8
+ import { MAX_REQUEST_FOR_RESOURCES } from './fetch_resources_constants.js';
9
+ import { isRelativeUrl } from '../../../utils/url_utils.js';
10
+ import { FetchResourcesErrorsFactory } from './fetch_resources_errors_factory.js';
11
+ import { move } from 'fs-extra';
12
+ export class FetchResources {
13
+ #urlsAttempts = {};
14
+ #httpApi;
15
+ constructor(httpApi) {
16
+ this.#httpApi = httpApi;
17
+ }
18
+ async fetchResources({ dist, resourcesPart, parts, shopUrl }) {
19
+ if (Array.isArray(resourcesPart)) {
20
+ for (let i = 0; i < resourcesPart.length; i++) {
21
+ const resource = resourcesPart[i];
22
+ if (isResourceObject(resource)) {
23
+ await this._fetchResource({
24
+ url: isRelativeUrl(resource.url) ? `${shopUrl}${resource.url}` : resource.url,
25
+ dist,
26
+ parts: [...parts, i],
27
+ shopUrl,
28
+ isPrivate: resource.isPrivate ?? false
29
+ });
30
+ continue;
31
+ }
32
+ await this.fetchResources({
33
+ dist,
34
+ resourcesPart: resourcesPart[i],
35
+ parts: [...parts, i],
36
+ shopUrl
37
+ });
38
+ }
39
+ return;
40
+ }
41
+ if (typeof resourcesPart === 'object') {
42
+ if (isResourceObject(resourcesPart)) {
43
+ await this._fetchResource({
44
+ url: isRelativeUrl(resourcesPart.url) ? `${shopUrl}${resourcesPart.url}` : resourcesPart.url,
45
+ dist,
46
+ parts,
47
+ shopUrl,
48
+ isPrivate: resourcesPart.isPrivate ?? false
49
+ });
50
+ return;
51
+ }
52
+ await Promise.all(Object.keys(resourcesPart).map((key) => {
53
+ return this.fetchResources({
54
+ dist,
55
+ resourcesPart: resourcesPart[key],
56
+ parts: [...parts, key],
57
+ shopUrl
58
+ });
59
+ }));
60
+ }
61
+ }
62
+ async _getResourcesFileContent(resourcePath) {
63
+ return mapResourcesToTree(await readJSONFile(resourcePath));
64
+ }
65
+ _getResourcesPart(resources, parts) {
66
+ return parts.reduce((acc, part) => acc[part] ?? {}, resources);
67
+ }
68
+ async _fetchResource({ url, shopUrl, parts, dist, isPrivate }) {
69
+ this.#urlsAttempts[url] = (this.#urlsAttempts[url] ?? 0) + 1;
70
+ if (this.#urlsAttempts[url] > MAX_REQUEST_FOR_RESOURCES)
71
+ throw FetchResourcesErrorsFactory.createErrorFetchingResource(shopUrl, [
72
+ `Failed to fetch ${url} after 3 attempts, for: ${parts.join('')}`
73
+ ]);
74
+ const { path: tmpDir } = await tmp.dir({ unsafeCleanup: true, prefix: 'theme_resources_tmp' });
75
+ try {
76
+ const { filename, ext, basename } = await downloadFile({
77
+ dist: tmpDir,
78
+ request: this._getRequest({ url, isPrivate }).response
79
+ });
80
+ if (ext === '.zip') {
81
+ await extractZip({
82
+ source: join(tmpDir, filename),
83
+ dist: join(tmpDir, basename)
84
+ });
85
+ if (!(await fileExists(getResourcesPath(join(tmpDir, basename)))))
86
+ return;
87
+ await copyFile(join(tmpDir, basename), dist, {
88
+ recursive: true,
89
+ force: true
90
+ });
91
+ const newResources = await this._getResourcesFileContent(getResourcesPath(join(tmpDir, basename)));
92
+ await this.fetchResources({
93
+ dist,
94
+ resourcesPart: this._getResourcesPart(newResources, parts),
95
+ parts,
96
+ shopUrl
97
+ });
98
+ }
99
+ else {
100
+ await move(join(tmpDir, filename), join(dist, this._getFilepathFromParts(parts), filename), { overwrite: true });
101
+ }
102
+ }
103
+ catch (err) {
104
+ throw FetchResourcesErrorsFactory.createErrorFetchingResource(shopUrl, err.message ? [err.message] : ['Unknown error']);
105
+ }
106
+ }
107
+ _getRequest({ url, isPrivate }) {
108
+ return this.#httpApi.fetch({
109
+ url,
110
+ method: REQUEST_TYPES.get,
111
+ //TODO tajping
112
+ //@ts-ignore
113
+ responseType: 'stream',
114
+ sanitizeOptions: {
115
+ disable: true
116
+ },
117
+ isPrivate
118
+ });
119
+ }
120
+ _getFilepathFromParts(parts) {
121
+ return parts
122
+ .filter((part) => typeof part === 'string')
123
+ .reduce((acc, part) => {
124
+ return join(acc, part);
125
+ }, '');
126
+ }
127
+ }
@@ -0,0 +1,2 @@
1
+ export const RESOURCES_FILE_NAME = 'resources.json';
2
+ export const MAX_REQUEST_FOR_RESOURCES = 3;
@@ -0,0 +1,11 @@
1
+ import { AppError } from '../../../cli/class/errors/app_error/app_error.js';
2
+ export class FetchResourcesErrorsFactory {
3
+ static createErrorFetchingResource(shopUrl, messages) {
4
+ return new AppError({
5
+ code: 'theme.fetch_resources.error_fetching_resource',
6
+ message: `Error while fetching resources from shop "${shopUrl}"`,
7
+ level: 'error',
8
+ details: messages
9
+ });
10
+ }
11
+ }