@shoper/cli 0.1.0-7 → 0.1.0-8

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 +126 -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 +124 -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 +194 -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 +31 -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 +187 -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 +152 -0
  109. package/build/utils/http_utils.js +10 -0
  110. package/build/utils/path_utils.js +34 -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 +34 -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,21 @@
1
+ import { Transform } from 'node:stream';
2
+ import { JSON_FILE_INDENT } from '../../cli/cli_constants.js';
3
+ export const jsonIndentTransform = (space = JSON_FILE_INDENT) => {
4
+ let data = '';
5
+ return new Transform({
6
+ writableObjectMode: true,
7
+ transform(chunk, _, callback) {
8
+ data += chunk.toString();
9
+ callback();
10
+ },
11
+ flush(callback) {
12
+ if (!data) {
13
+ return callback();
14
+ }
15
+ const json = JSON.parse(data);
16
+ const pretty = JSON.stringify(json, null, space);
17
+ this.push(pretty);
18
+ callback();
19
+ }
20
+ });
21
+ };
@@ -0,0 +1,9 @@
1
+ export const isRelativeUrl = (url) => {
2
+ try {
3
+ const test = new URL(url, 'http://example.com');
4
+ return test.origin === 'http://example.com' && !url.startsWith('//');
5
+ }
6
+ catch {
7
+ return true;
8
+ }
9
+ };
@@ -0,0 +1,80 @@
1
+ import process from 'process';
2
+ import { fileExists, isDirectory, removeFiles } from '../fs/fs_utils.js';
3
+ import yazl from 'yazl';
4
+ import { createWriteStream } from 'node:fs';
5
+ import { StreamReadError } from '../fs/errors/stream_read_error.js';
6
+ import { CreateZipError } from './errors/create_zip_error.js';
7
+ import { StreamWriteError } from '../fs/errors/stream_write_error.js';
8
+ import { join } from '../path_utils.js';
9
+ import { AppError } from '../../cli/class/errors/app_error/app_error.js';
10
+ export const createZip = async ({ files, dist, baseDir = process.cwd() }) => {
11
+ const zipfile = new yazl.ZipFile();
12
+ let hasError = false;
13
+ try {
14
+ for (let i = 0; i < files.length; ++i) {
15
+ const file = files[i];
16
+ if (!file)
17
+ continue;
18
+ const fullPath = join(baseDir, file);
19
+ if (!(await fileExists(fullPath)))
20
+ throw new AppError({
21
+ message: `File does not exist: ${fullPath}`,
22
+ code: 'FILE_NOT_FOUND',
23
+ details: { file, baseDir }
24
+ });
25
+ if (await isDirectory(fullPath)) {
26
+ zipfile.addEmptyDirectory(file);
27
+ }
28
+ else {
29
+ zipfile.addFile(fullPath, file, {
30
+ //TODO params
31
+ compress: true
32
+ });
33
+ }
34
+ }
35
+ zipfile.end();
36
+ }
37
+ catch (err) {
38
+ throw new AppError({
39
+ message: 'Error creating zip file',
40
+ code: 'ZIP_CREATION_ERROR',
41
+ details: { files, dist, baseDir },
42
+ stack: err instanceof Error ? err.stack : undefined
43
+ });
44
+ }
45
+ return new Promise((resolve, reject) => {
46
+ const zipOutput = createWriteStream(dist);
47
+ zipOutput.on('error', (err) => {
48
+ hasError = true;
49
+ removeFiles(files).then(() => {
50
+ reject(new StreamWriteError({
51
+ filePath: dist,
52
+ details: { err },
53
+ stack: err.stack
54
+ }));
55
+ });
56
+ });
57
+ zipfile.outputStream.pipe(zipOutput).on('close', () => {
58
+ if (hasError) {
59
+ removeFiles(files).then(() => {
60
+ reject(new CreateZipError({
61
+ file: dist,
62
+ stack: new Error().stack
63
+ }));
64
+ });
65
+ return;
66
+ }
67
+ resolve();
68
+ });
69
+ zipfile.outputStream.on('error', (err) => {
70
+ hasError = true;
71
+ removeFiles(files).then(() => {
72
+ reject(new StreamReadError({
73
+ filePath: dist,
74
+ details: { err },
75
+ stack: err.stack
76
+ }));
77
+ });
78
+ });
79
+ });
80
+ };
@@ -0,0 +1,11 @@
1
+ import { AppError } from '../../../cli/class/errors/app_error/app_error.js';
2
+ export class CreateZipError extends AppError {
3
+ constructor({ details, stack, file }) {
4
+ super({
5
+ code: 'ZIP_FILE_CREATE_ERROR',
6
+ message: `Error creating zip file ${file}`,
7
+ details,
8
+ stack
9
+ });
10
+ }
11
+ }
@@ -0,0 +1,11 @@
1
+ import { AppError } from '../../../cli/class/errors/app_error/app_error.js';
2
+ export class OpenZipError extends AppError {
3
+ constructor({ details, stack, file }) {
4
+ super({
5
+ code: 'ZIP_FILE_OPEN_ERROR',
6
+ message: `Error opening zip file ${file}`,
7
+ details,
8
+ stack
9
+ });
10
+ }
11
+ }
@@ -0,0 +1,104 @@
1
+ import yauzl from 'yauzl';
2
+ import { directoryExists, makeDirectory, removeDirectory, removeDirectorySync, removeFile } from '../fs/fs_utils.js';
3
+ import { dirname, join, looksLikeDirectory } from '../path_utils.js';
4
+ import { createWriteStream } from 'node:fs';
5
+ import { StreamWriteError } from '../fs/errors/stream_write_error.js';
6
+ import { StreamReadError } from '../fs/errors/stream_read_error.js';
7
+ import { OpenZipError } from './errors/open_zip_error.js';
8
+ import { pipeline } from 'node:stream/promises';
9
+ export const extractZip = async ({ source, dist, getTransforms = () => [] }) => {
10
+ let createdDirectory = false;
11
+ if (!(await directoryExists(dist))) {
12
+ createdDirectory = true;
13
+ await makeDirectory(dist, { recursive: true });
14
+ }
15
+ return new Promise((resolve, reject) => {
16
+ const processedFilesPath = [];
17
+ yauzl.open(source, { lazyEntries: true }, (err, zipfile) => {
18
+ if (err) {
19
+ createdDirectory && removeDirectorySync(dist, { recursive: true });
20
+ return reject(new OpenZipError({
21
+ file: source,
22
+ details: { err },
23
+ stack: err.stack
24
+ }));
25
+ }
26
+ let activeEntries = 0;
27
+ let doneReadingEntries = false;
28
+ const extractedPaths = new Set();
29
+ zipfile.on('entry', (entry) => {
30
+ activeEntries++;
31
+ const filePath = join(dist, entry.fileName);
32
+ const dirPath = dirname(filePath);
33
+ processedFilesPath.push(filePath);
34
+ if (!filePath.startsWith(dist)) {
35
+ return reject(new Error(`Invalid entry path: ${entry.fileName}`));
36
+ }
37
+ if (looksLikeDirectory(entry.fileName)) {
38
+ zipfile.readEntry();
39
+ return;
40
+ }
41
+ if (extractedPaths.has(filePath)) {
42
+ return reject(new Error(`Duplicate entry path detected: ${filePath}`));
43
+ }
44
+ extractedPaths.add(filePath);
45
+ makeDirectory(dirPath, { recursive: true })
46
+ .then(() => {
47
+ zipfile.openReadStream(entry, async (err, readStream) => {
48
+ if (err)
49
+ return reject(err);
50
+ const writeStream = createWriteStream(filePath);
51
+ writeStream.on('finish', () => {
52
+ activeEntries--;
53
+ if (activeEntries === 0 && doneReadingEntries)
54
+ resolve();
55
+ zipfile.readEntry();
56
+ });
57
+ writeStream.on('error', async (err) => {
58
+ await removeFile(filePath);
59
+ reject(new StreamWriteError({
60
+ filePath,
61
+ details: { err },
62
+ stack: err.stack
63
+ }));
64
+ });
65
+ readStream.on('error', async (err) => {
66
+ await removeFile(filePath, { force: true });
67
+ reject(new StreamReadError({
68
+ filePath,
69
+ details: { err },
70
+ stack: err.stack
71
+ }));
72
+ });
73
+ const transforms = getTransforms(entry.fileName);
74
+ if (transforms.length) {
75
+ await pipeline(readStream, ...transforms, writeStream);
76
+ }
77
+ else {
78
+ readStream.pipe(writeStream);
79
+ }
80
+ });
81
+ })
82
+ .catch(reject);
83
+ });
84
+ zipfile.on('end', () => {
85
+ doneReadingEntries = true;
86
+ if (activeEntries === 0)
87
+ resolve();
88
+ });
89
+ zipfile.on('error', async (err) => {
90
+ for (const filePath of processedFilesPath) {
91
+ try {
92
+ await removeFile(filePath, { force: true });
93
+ }
94
+ catch (removeErr) {
95
+ console.error(`Error removing file ${filePath}:`, removeErr);
96
+ }
97
+ }
98
+ createdDirectory && (await removeDirectory(dist, { recursive: true }));
99
+ reject(err);
100
+ });
101
+ zipfile.readEntry();
102
+ });
103
+ });
104
+ };
package/oclif.config.js CHANGED
@@ -17,8 +17,10 @@ export default {
17
17
  hooks: {
18
18
  prerun: [
19
19
  './build/cli/hooks/authorization/ensure_authorization_hook.js',
20
- './build/cli/hooks/migration/migration_hook.js',
21
- './build/cli/hooks/ensure_cli_initialized_hook.js'
20
+ './build/cli/hooks/ensure_cli_initialized_hook.js',
21
+ './build/theme/hooks/ensure_theme_meta_data_untouched.js',
22
+ './build/theme/hooks/ensure_theme_current_checksums_up_to_date.js',
23
+ './build/theme/hooks/themes_actions/ensure_themes_actions_hook.js'
22
24
  ]
23
25
  },
24
26
  topicSeparator: ' ',
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@shoper/cli",
3
3
  "packageManager": "yarn@3.2.0",
4
4
  "sideEffects": false,
5
- "version": "0.1.0-7",
5
+ "version": "0.1.0-8",
6
6
  "description": "CLI tool for Shoper",
7
7
  "author": "Joanna Firek",
8
8
  "license": "MIT",
@@ -24,13 +24,13 @@
24
24
  "scripts": {
25
25
  "build": "rimraf ./build/ && tsc --project tsconfig.json",
26
26
  "watch": "rimraf ./build/ && tsc --watch --project tsconfig.json",
27
- "test": "vitest --config config/vitest/vitest.config.ts --watch=false",
28
- "test:watch": "vitest --config config/vitest/vitest.config.ts --watch=true",
27
+ "test": "jest --config config/jest/jest.config.mjs",
28
+ "test:watch": "jest --config config/jest/jest.config.mjs --no-cache --watch",
29
29
  "deploy:latest": "npm run build && npm publish --tag latest --access public",
30
30
  "deploy:beta": "npm run build && npm publish --tag beta --access public"
31
31
  },
32
32
  "dependencies": {
33
- "@dreamcommerce/star_core": "1.7.7",
33
+ "@dreamcommerce/star_core": "1.8.1",
34
34
  "@oclif/core": "4.2.10",
35
35
  "@oclif/plugin-autocomplete": "3.2.27",
36
36
  "@oclif/plugin-help": "6.2.27",
@@ -38,29 +38,56 @@
38
38
  "@oclif/plugin-version": "2.2.27",
39
39
  "@oclif/plugin-warn-if-update-available": "3.1.38",
40
40
  "axios": "1.8.4",
41
+ "chalk": "5.4.1",
42
+ "conf": "13.1.0",
43
+ "ink": "5.2.1",
44
+ "inquirer": "12.5.2",
41
45
  "is-hidden-file": "1.1.2",
46
+ "jsonwebtoken": "9.0.2",
42
47
  "memfs": "4.17.0",
48
+ "ora": "8.2.0",
49
+ "react": "18.3.1",
43
50
  "reflect-metadata": "0.2.2",
44
51
  "rxjs": "7.8.2",
45
52
  "semver": "7.7.1",
46
53
  "tmp-promise": "3.0.3",
47
- "unzipper": "0.12.3"
54
+ "yauzl": "3.2.0",
55
+ "yazl": "3.3.1",
56
+ "fs-tree-diff": "2.0.1",
57
+ "fast-glob": "3.3.3",
58
+ "klaw": "4.1.0",
59
+ "walk-sync": "3.0.0",
60
+ "lodash": "4.17.21",
61
+ "uuid": "11.1.0"
48
62
  },
49
63
  "devDependencies": {
64
+ "@babel/core": "7.27.1",
65
+ "@babel/preset-env": "7.27.2",
66
+ "@babel/preset-typescript": "7.27.1",
50
67
  "@oclif/test": "4.1.12",
51
68
  "@tsconfig/node18": "18.2.4",
69
+ "@types/jest": "29.5.14",
70
+ "@types/jsonwebtoken": "9.0.9",
52
71
  "@types/node": "18.19.84",
72
+ "@types/react": "19.1.3",
53
73
  "@types/semver": "7.7.0",
54
74
  "@types/tmp": "0.2.6",
55
- "@types/unzipper": "0.10.11",
75
+ "@types/yauzl": "2.10.3",
76
+ "@types/yazl": "2.4.6",
77
+ "@types/klaw": "3.0.7",
78
+ "@types/lodash": "4.17.17",
56
79
  "@typescript-eslint/eslint-plugin": "8.29.1",
80
+ "babel-jest": "29.7.0",
57
81
  "eslint": "9.24.0",
58
82
  "eslint-config-prettier": "10.1.1",
59
83
  "eslint-plugin-prettier": "5.2.6",
84
+ "jest": "29.7.0",
60
85
  "module-alias": "2.2.3",
61
86
  "prettier": "3.5.3",
62
87
  "rimraf": "5.0.10",
88
+ "ts-jest": "29.3.2",
89
+ "ts-toolbelt": "9.6.0",
63
90
  "typescript": "5.8.3",
64
- "vitest": "3.1.1"
91
+ "jest-extended": "4.0.2"
65
92
  }
66
93
  }
@@ -1,4 +0,0 @@
1
- const migrationHook = async () => {
2
- //TODO
3
- };
4
- export default migrationHook;
@@ -1,12 +0,0 @@
1
- import { BaseThemeCommand } from '../class/base_theme_command.js';
2
- import { SHOPER_THEMES_API_NAME } from '../features/themes/shoper_themes_constants.js';
3
- export class ThemeListCommand extends BaseThemeCommand {
4
- static description = 'List all shop themes';
5
- async run() {
6
- const themesApi = this.getApi(SHOPER_THEMES_API_NAME);
7
- // TODO get credentials from api
8
- const themes = await themesApi.getThemes('https://shoper.docker.shoper.tech');
9
- //TODO UI
10
- this.log('themes', themes);
11
- }
12
- }
@@ -1,24 +0,0 @@
1
- import { Args } from '@oclif/core';
2
- import { BaseThemeCommand } from '../class/base_theme_command.js';
3
- export class ThemePullCommand extends BaseThemeCommand {
4
- static description = 'Pull theme from shop';
5
- static args = {
6
- id: Args.string({
7
- description: 'Theme id',
8
- name: 'id',
9
- required: true,
10
- type: 'string'
11
- })
12
- };
13
- async run() {
14
- const data = await this.parse(ThemePullCommand);
15
- const { args } = data;
16
- //TODO sprawdamy z lista sików przed pullem?
17
- //TDOO jezeli nie ma id, pobierz z kontekstu jezeli jest w theme
18
- const themeId = args.id;
19
- // TODO some automation
20
- // const themePullApi = new ShoperThemePullInitializer().init();
21
- // TODO get credentials from api
22
- // await themePullApi.pullTheme('https://shoper.docker.shoper.tech', themeId);
23
- }
24
- }
@@ -1,10 +0,0 @@
1
- import { getAllDirectoriesInside } from '../../../../utils/fs.js';
2
- import { join } from '../../../../utils/path.js';
3
- import { ThemeDirectoryUtils } from './theme_directory_utils.js';
4
- import { asyncFilter } from '../../../../utils/array_utils.js';
5
- export class ThemeDirectoriesUtils {
6
- static async getAllThemesDirectories(path) {
7
- const directories = await getAllDirectoriesInside(path);
8
- return asyncFilter(directories, async (directory) => ThemeDirectoryUtils.isThemeRootDirectory(join(path, directory)));
9
- }
10
- }
@@ -1,9 +0,0 @@
1
- export class ShoperThemePullApi {
2
- #service;
3
- constructor(service) {
4
- this.#service = service;
5
- }
6
- async pullTheme(shopUrl, id) {
7
- return this.#service.pullTheme(shopUrl, id);
8
- }
9
- }
@@ -1,14 +0,0 @@
1
- //TODO
2
- export class ShoperThemePullHttpApi {
3
- #httpApi;
4
- constructor(httpApi) {
5
- this.#httpApi = httpApi;
6
- }
7
- pullTheme(shopUrl, id) {
8
- const controller = new AbortController();
9
- const resp = fetch(`${shopUrl}/webapi/cli/themes/${id}`, {
10
- signal: controller.signal
11
- });
12
- return { response: resp, controller };
13
- }
14
- }
@@ -1,68 +0,0 @@
1
- import { createWriteStream } from 'fs';
2
- import { basename, extname } from '../../../../../utils/path.js';
3
- import unzipper from 'unzipper';
4
- import tmp from 'tmp-promise';
5
- import { EXECUTION_CONTEXTS } from '../../../../../cli/features/execution_context/execution_context_constants.js';
6
- //TODO fix
7
- let currentRequest;
8
- export class ShoperThemePullService {
9
- #httpApi;
10
- #executionContext;
11
- constructor({ httpApi, executionContext }) {
12
- this.#httpApi = httpApi;
13
- this.#executionContext = executionContext;
14
- }
15
- async pullTheme(shopUrl, id) {
16
- if (currentRequest)
17
- currentRequest.abort();
18
- //TODO error handling
19
- const { response, controller } = this.#httpApi.pullTheme(shopUrl, id);
20
- currentRequest = controller;
21
- const resp = await response;
22
- if (resp.status === 405) {
23
- //TODO not authenticated
24
- throw new Error('Theme not found');
25
- }
26
- if (resp.status !== 200) {
27
- //TODO handle error
28
- throw new Error('Theme not found');
29
- }
30
- const { path, cleanup } = await tmp.dir({
31
- unsafeCleanup: true
32
- });
33
- const filename = /filename="([^"]+)"/.exec(resp.headers.get('content-disposition') ?? '')?.[1];
34
- if (!filename) {
35
- //TODO handle error
36
- throw new Error(`Missing Filename in a content-disposition header ${resp.headers.get('content-disposition') ?? ''}`);
37
- }
38
- const file = createWriteStream(`${path}/${filename}`);
39
- file.on('finish', async () => {
40
- file.close();
41
- await this._extractToSpecificDirectory(file.path, path);
42
- await cleanup();
43
- });
44
- file.on('error', (err) => {
45
- console.log('err', err);
46
- //TODO
47
- });
48
- //@ts-ignore
49
- resp.body?.pipe(file);
50
- }
51
- async _extractToSpecificDirectory(archivePath, tmpDir) {
52
- console.log('executionContext', this.#executionContext);
53
- const filenameWithoutExtension = basename(archivePath, extname(archivePath));
54
- const directory = await unzipper.Open.file(archivePath);
55
- await directory.extract({ path: `${tmpDir}/${filenameWithoutExtension}` });
56
- //TODO check if theme exist
57
- if (this.#executionContext.type === EXECUTION_CONTEXTS.global) {
58
- //czek if folder exist
59
- //czek if theme + shop exist
60
- //if folder not exist create
61
- // if folder exist clear images file
62
- // fetch images while copying theme
63
- }
64
- if (this.#executionContext.type === EXECUTION_CONTEXTS.theme) {
65
- //TODO save in storage
66
- }
67
- }
68
- }
@@ -1,22 +0,0 @@
1
- import { ShoperThemePullService } from './service/shoper_theme_pull_service.js';
2
- import { ShoperThemePullHttpApi } from './http/shoper_theme_pull_http_api.js';
3
- import { ShoperThemePullApi } from './api/shoper_theme_pull_api.js';
4
- import { AsyncFeatureInitializer, FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME } from '@dreamcommerce/star_core';
5
- export class ShoperThemePullInitializer extends AsyncFeatureInitializer {
6
- async init() {
7
- const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
8
- const executionContextApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
9
- const service = new ShoperThemePullService({
10
- httpApi: new ShoperThemePullHttpApi(httpApi),
11
- executionContext: await executionContextApi.getExecutionContext()
12
- });
13
- return {
14
- cores: [
15
- {
16
- type: FEATURE_CORES_TYPES.api,
17
- instance: new ShoperThemePullApi(service)
18
- }
19
- ]
20
- };
21
- }
22
- }
@@ -1,14 +0,0 @@
1
- import { FeatureApi } from '@dreamcommerce/star_core';
2
- import { SHOPER_THEMES_API_NAME } from '../shoper_themes_constants.js';
3
- export class ShoperThemesApi extends FeatureApi {
4
- moduleName = SHOPER_THEMES_API_NAME;
5
- #service;
6
- constructor(service) {
7
- super();
8
- this.#service = service;
9
- }
10
- //credentialObject
11
- async getThemes(shopUrl) {
12
- return this.#service.getThemes(shopUrl);
13
- }
14
- }
@@ -1,15 +0,0 @@
1
- import { STATUS_CODES } from '@dreamcommerce/star_core';
2
- export class ShoperThemesService {
3
- httpApi;
4
- constructor(httpApi) {
5
- this.httpApi = httpApi;
6
- }
7
- async getThemes(shopUrl) {
8
- //TODO error handling
9
- const { response } = this.httpApi.getThemes(shopUrl);
10
- const { data, status } = await response;
11
- if (status !== STATUS_CODES.ok)
12
- return;
13
- return data;
14
- }
15
- }
@@ -1,2 +0,0 @@
1
- export const SHOPER_THEMES_FEATURE_NAME = 'ShoperThemes';
2
- export const SHOPER_THEMES_API_NAME = 'ShoperThemesApi';
@@ -1,20 +0,0 @@
1
- import { ShoperThemesService } from './services/shoper_themes_service.js';
2
- import { ShoperThemesApi } from './api/shoper_themes_api.js';
3
- import { ShoperThemesHttpApi } from './http/shoper_themes_http_api.js';
4
- import { FEATURE_CORES_TYPES, HTTP_REQUESTER_API_NAME, SyncFeatureInitializer } from '@dreamcommerce/star_core';
5
- import { SHOPER_THEMES_FEATURE_NAME } from './shoper_themes_constants.js';
6
- export class ShoperThemesInitializer extends SyncFeatureInitializer {
7
- static featureName = SHOPER_THEMES_FEATURE_NAME;
8
- init() {
9
- const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
10
- const service = new ShoperThemesService(new ShoperThemesHttpApi(httpApi));
11
- return {
12
- cores: [
13
- {
14
- type: FEATURE_CORES_TYPES.api,
15
- instance: new ShoperThemesApi(service)
16
- }
17
- ]
18
- };
19
- }
20
- }
package/build/utils/fs.js DELETED
@@ -1,44 +0,0 @@
1
- import fsPromises from 'fs/promises';
2
- import { isHiddenFile } from 'is-hidden-file';
3
- import process from 'process';
4
- import { resolve } from './path.js';
5
- import { parse as parsePath } from 'path';
6
- export const fileExists = async (path) => {
7
- try {
8
- await fsPromises.access(path);
9
- return true;
10
- }
11
- catch {
12
- return false;
13
- }
14
- };
15
- export const directoryExists = async (path) => {
16
- return fileExists(path);
17
- };
18
- export const readFile = async (path, options) => {
19
- return fsPromises.readFile(path, options);
20
- };
21
- export const makeDirectory = async (path, options = {}) => {
22
- return await fsPromises.mkdir(path, { recursive: false, ...options });
23
- };
24
- export const getAllDirectoriesInside = async (path, { hidden } = { hidden: true }) => {
25
- const files = await fsPromises.readdir(path, {
26
- recursive: true,
27
- withFileTypes: true
28
- });
29
- return files.filter((file) => file.isDirectory() && (hidden ? true : !isHiddenFile(file.name))).map((file) => file.name);
30
- };
31
- export const closestFile = async (fileToFind, path = process.cwd()) => {
32
- let currPath = path;
33
- const rootDir = getOSRootDirectory();
34
- while (currPath !== rootDir) {
35
- const exists = await fileExists(resolve(currPath, fileToFind));
36
- if (exists)
37
- return currPath;
38
- currPath = resolve(currPath, '..');
39
- }
40
- };
41
- export const closestDirectory = async (path) => {
42
- return closestFile(path);
43
- };
44
- export const getOSRootDirectory = () => parsePath(process.cwd()).root;
@@ -1,13 +0,0 @@
1
- import { resolve as resolvePath, parse as parsePath, join as pathJoin, basename as pathBaseName, dirname as pathDirname, extname as pathExtname } from 'path';
2
- export const resolve = (...paths) => {
3
- return resolvePath(...paths);
4
- };
5
- export const parse = (path) => {
6
- return parsePath(path);
7
- };
8
- export const join = (...paths) => {
9
- return pathJoin(...paths);
10
- };
11
- export const basename = (path, ext) => pathBaseName(path, ext);
12
- export const dirname = (path) => pathDirname(path);
13
- export const extname = (path) => pathExtname(path);