@shoper/cli 0.9.4-2 → 0.9.4-3
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/theme/commands/publish/theme_publish_command.js +201 -18
- package/build/theme/features/theme/skinstore/api/theme_skinstore_api.js +4 -4
- package/build/theme/features/theme/skinstore/http/theme_skinstore_http_api.js +26 -0
- package/build/theme/features/theme/skinstore/service/theme_skinstore_service.js +64 -12
- package/build/theme/features/theme/skinstore/theme_publish_constants.js +4 -0
- package/build/theme/features/theme/skinstore/theme_skinstore_initialzier.js +6 -1
- package/build/theme/index.js +2 -0
- package/package.json +2 -3
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Args } from '@oclif/core';
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
2
|
import { BaseThemeCommand } from '../../class/base_theme_command.js';
|
|
3
3
|
import { CLI_AUTH_API_NAME } from '../../../cli/auth/cli_auth_constants.js';
|
|
4
4
|
import { THEME_ACTIONS_API_NAME, THEME_ACTIONS_TYPES } from '../../features/theme/actions/theme_actions_constants.js';
|
|
@@ -7,20 +7,41 @@ import { renderOnce } from '../../../ui/ui_utils.js';
|
|
|
7
7
|
import { MissingCredentialsError } from '../../../cli/commands/auth/ui/missing_credentials_error.js';
|
|
8
8
|
import React from 'react';
|
|
9
9
|
import { MissingThemeIdError } from '../ui/missing_theme_id_error.js';
|
|
10
|
-
import { THEME_SKINSTORE_API_NAME } from '../../features/theme/skinstore/theme_publish_constants.js';
|
|
10
|
+
import { THEME_SKINSTORE_API_NAME, RELEASE_TYPE_TEST, RELEASE_TYPE_STABLE, IMAGE_MAX_SIZE, IMAGE_ALLOWED_EXTENSIONS } from '../../features/theme/skinstore/theme_publish_constants.js';
|
|
11
11
|
import { Form } from '../../../cli/features/controls/ui/form.js';
|
|
12
|
+
import { toInquirerControls } from '../../../cli/features/controls/ui/controls_mappers.js';
|
|
12
13
|
import { ThemeError } from '../ui/theme_error.js';
|
|
13
14
|
import { LOGGER_API_NAME } from '../../../cli/utilities/features/logger/logger_constants.js';
|
|
15
|
+
import { Text } from '../../../ui/text.js';
|
|
16
|
+
import { Box } from '../../../ui/box.js';
|
|
17
|
+
import { Success } from '../../../ui/message_box/success.js';
|
|
18
|
+
import { Info } from '../../../ui/message_box/info.js';
|
|
19
|
+
import { Error as ErrorBox } from '../../../ui/message_box/error.js';
|
|
20
|
+
import { UnpermittedCommandError } from '../ui/unpermitted_command_error.js';
|
|
21
|
+
import { promptConfirmation } from '../../../ui/prompts/prompt_confirmation.js';
|
|
22
|
+
import fs from 'fs';
|
|
23
|
+
import path from 'path';
|
|
14
24
|
export class ThemePublishCommand extends BaseThemeCommand {
|
|
15
|
-
static summary = '
|
|
16
|
-
static description = '
|
|
25
|
+
static summary = 'Publish theme to SkinStore.';
|
|
26
|
+
static description = 'Publishes a theme to the Shoper SkinStore marketplace.\n\nFor first-time publication, you will be prompted to fill in theme details.\nFor already published themes, this performs an upgrade (new version).';
|
|
17
27
|
static examples = [
|
|
18
28
|
{
|
|
19
|
-
description: '
|
|
29
|
+
description: 'Publish current theme (from theme directory)',
|
|
30
|
+
command: '<%= config.bin %> <%= command.id %>'
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
description: 'Publish specific theme by ID',
|
|
20
34
|
command: '<%= config.bin %> <%= command.id %> 123'
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
description: 'Publish as test release',
|
|
38
|
+
command: '<%= config.bin %> <%= command.id %> --release test'
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
description: 'Publish with screenshots from directory',
|
|
42
|
+
command: '<%= config.bin %> <%= command.id %> --images ./screenshots'
|
|
21
43
|
}
|
|
22
44
|
];
|
|
23
|
-
static hidden = true;
|
|
24
45
|
static args = {
|
|
25
46
|
id: Args.string({
|
|
26
47
|
description: 'Theme id',
|
|
@@ -29,6 +50,18 @@ export class ThemePublishCommand extends BaseThemeCommand {
|
|
|
29
50
|
type: 'string'
|
|
30
51
|
})
|
|
31
52
|
};
|
|
53
|
+
static flags = {
|
|
54
|
+
release: Flags.string({
|
|
55
|
+
char: 'r',
|
|
56
|
+
description: 'Release type',
|
|
57
|
+
options: ['test', 'stable'],
|
|
58
|
+
default: 'stable'
|
|
59
|
+
}),
|
|
60
|
+
images: Flags.string({
|
|
61
|
+
char: 'i',
|
|
62
|
+
description: 'Path to directory with screenshots'
|
|
63
|
+
})
|
|
64
|
+
};
|
|
32
65
|
async run() {
|
|
33
66
|
const themeId = this.args.id;
|
|
34
67
|
const cliAuthApi = this.getApi(CLI_AUTH_API_NAME);
|
|
@@ -43,32 +76,59 @@ export class ThemePublishCommand extends BaseThemeCommand {
|
|
|
43
76
|
try {
|
|
44
77
|
let _themeId = themeId;
|
|
45
78
|
if (executionContext.type !== EXECUTION_CONTEXTS.theme && !_themeId) {
|
|
79
|
+
renderOnce(React.createElement(MissingThemeIdError, null,
|
|
80
|
+
React.createElement(Box, { flexDirection: "column", gap: 1 },
|
|
81
|
+
React.createElement(Text, null, "Usage: shoper theme publish [ID]"),
|
|
82
|
+
React.createElement(Text, null, "Please run this command inside a theme directory or provide a theme ID."))));
|
|
46
83
|
return;
|
|
47
84
|
}
|
|
48
|
-
if (executionContext.type === EXECUTION_CONTEXTS.theme)
|
|
85
|
+
if (executionContext.type === EXECUTION_CONTEXTS.theme)
|
|
49
86
|
_themeId = _themeId ?? executionContext.themeId;
|
|
50
|
-
}
|
|
51
87
|
if (!_themeId) {
|
|
52
88
|
renderOnce(React.createElement(MissingThemeIdError, null));
|
|
53
89
|
return;
|
|
54
90
|
}
|
|
55
91
|
const themeActionsApi = this.getApi(THEME_ACTIONS_API_NAME);
|
|
56
92
|
const themeSkinstoreApi = this.getApi(THEME_SKINSTORE_API_NAME);
|
|
57
|
-
const
|
|
58
|
-
actionType: THEME_ACTIONS_TYPES.
|
|
93
|
+
const publishAction = themeActionsApi.getThemeAction({
|
|
94
|
+
actionType: THEME_ACTIONS_TYPES.publish,
|
|
59
95
|
themeId: _themeId,
|
|
60
96
|
credentials
|
|
61
97
|
});
|
|
62
|
-
|
|
63
|
-
|
|
98
|
+
if (!publishAction) {
|
|
99
|
+
renderOnce(React.createElement(UnpermittedCommandError, { themeId: _themeId, commandName: "publish" }));
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const publishFormAction = themeActionsApi.getThemeAction({
|
|
103
|
+
actionType: THEME_ACTIONS_TYPES.publishForm,
|
|
104
|
+
themeId: _themeId,
|
|
64
105
|
credentials
|
|
65
106
|
});
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
107
|
+
const releaseType = this.flags.release === 'test' ? RELEASE_TYPE_TEST : RELEASE_TYPE_STABLE;
|
|
108
|
+
const isUpgrade = !publishFormAction;
|
|
109
|
+
if (isUpgrade) {
|
|
110
|
+
await this.#handleUpgrade({
|
|
111
|
+
themeSkinstoreApi,
|
|
112
|
+
themeActionsApi,
|
|
113
|
+
publishAction,
|
|
114
|
+
credentials,
|
|
115
|
+
releaseType,
|
|
116
|
+
themeId: _themeId,
|
|
117
|
+
loggerApi
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
await this.#handleFirstPublish({
|
|
122
|
+
themeSkinstoreApi,
|
|
123
|
+
themeActionsApi,
|
|
124
|
+
publishFormAction,
|
|
125
|
+
publishAction,
|
|
126
|
+
credentials,
|
|
127
|
+
releaseType,
|
|
128
|
+
themeId: _themeId,
|
|
129
|
+
loggerApi
|
|
130
|
+
});
|
|
131
|
+
}
|
|
72
132
|
}
|
|
73
133
|
catch (err) {
|
|
74
134
|
loggerApi.error('Theme publish command error:', {
|
|
@@ -77,4 +137,127 @@ export class ThemePublishCommand extends BaseThemeCommand {
|
|
|
77
137
|
renderOnce(React.createElement(ThemeError, { err: err, executionContext: executionContext }));
|
|
78
138
|
}
|
|
79
139
|
}
|
|
140
|
+
async #handleUpgrade({ themeSkinstoreApi, themeActionsApi, publishAction, credentials, releaseType, themeId, loggerApi }) {
|
|
141
|
+
renderOnce(React.createElement(Info, { header: `Upgrading published theme (ID: ${themeId})` },
|
|
142
|
+
React.createElement(Text, null,
|
|
143
|
+
"Release type: ",
|
|
144
|
+
this.flags.release)));
|
|
145
|
+
const { proceed } = await promptConfirmation('Proceed with upgrade?');
|
|
146
|
+
if (!proceed) {
|
|
147
|
+
renderOnce(React.createElement(Info, { header: "Theme publish was cancelled." }));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const result = await themeSkinstoreApi.publishTheme({
|
|
151
|
+
actionData: publishAction.data,
|
|
152
|
+
credentials,
|
|
153
|
+
payload: { release: releaseType }
|
|
154
|
+
});
|
|
155
|
+
if (result?.isSuccess) {
|
|
156
|
+
themeActionsApi.removeThemeActions({ themeId, credentials });
|
|
157
|
+
renderOnce(React.createElement(Success, { header: "Theme upgraded successfully!" },
|
|
158
|
+
React.createElement(Text, null,
|
|
159
|
+
"Release type: ",
|
|
160
|
+
this.flags.release)));
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
this.#renderPublishErrors(result?.messages);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async #handleFirstPublish({ themeSkinstoreApi, themeActionsApi, publishFormAction, publishAction, credentials, releaseType, themeId, loggerApi }) {
|
|
167
|
+
const controls = await themeSkinstoreApi.getPublishFormData({
|
|
168
|
+
actionData: publishFormAction.data,
|
|
169
|
+
credentials
|
|
170
|
+
});
|
|
171
|
+
if (!controls || controls.length === 0) {
|
|
172
|
+
renderOnce(React.createElement(ErrorBox, { header: "Could not fetch publish form." },
|
|
173
|
+
React.createElement(Text, null, "Check if SkinStore SDK feature is enabled for your store.")));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const inquirerControls = toInquirerControls(controls.filter((c) => c.name !== 'release'));
|
|
177
|
+
const formData = await new Promise((resolve) => {
|
|
178
|
+
Form({
|
|
179
|
+
controls: inquirerControls,
|
|
180
|
+
onSubmit: resolve
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
let uploadedImageIds = [];
|
|
184
|
+
if (this.flags.images) {
|
|
185
|
+
uploadedImageIds = await this.#uploadImages({
|
|
186
|
+
themeSkinstoreApi,
|
|
187
|
+
credentials,
|
|
188
|
+
imagesDir: this.flags.images,
|
|
189
|
+
skinId: themeId,
|
|
190
|
+
loggerApi
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const payload = {
|
|
194
|
+
name: formData.name,
|
|
195
|
+
desc: formData.desc ?? '',
|
|
196
|
+
description: formData.description,
|
|
197
|
+
categories: Array.isArray(formData.categories) ? formData.categories : [formData.categories],
|
|
198
|
+
colors: Array.isArray(formData.colors) ? formData.colors : [formData.colors],
|
|
199
|
+
price: Number(formData.price) || 0,
|
|
200
|
+
release: releaseType,
|
|
201
|
+
...(uploadedImageIds.length > 0 ? { filesList: uploadedImageIds } : {})
|
|
202
|
+
};
|
|
203
|
+
const result = await themeSkinstoreApi.publishTheme({
|
|
204
|
+
actionData: publishAction.data,
|
|
205
|
+
credentials,
|
|
206
|
+
payload
|
|
207
|
+
});
|
|
208
|
+
if (result?.isSuccess) {
|
|
209
|
+
themeActionsApi.removeThemeActions({ themeId, credentials });
|
|
210
|
+
renderOnce(React.createElement(Success, { header: "Theme published successfully!" },
|
|
211
|
+
React.createElement(Text, null, "Your theme is now available on SkinStore.")));
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
this.#renderPublishErrors(result?.messages);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
async #uploadImages({ themeSkinstoreApi, credentials, imagesDir, skinId, loggerApi }) {
|
|
218
|
+
const imageIds = [];
|
|
219
|
+
if (!fs.existsSync(imagesDir)) {
|
|
220
|
+
renderOnce(React.createElement(ErrorBox, { header: "Images directory not found." },
|
|
221
|
+
React.createElement(Text, null,
|
|
222
|
+
"Path: ",
|
|
223
|
+
imagesDir)));
|
|
224
|
+
return imageIds;
|
|
225
|
+
}
|
|
226
|
+
const files = fs.readdirSync(imagesDir).filter((file) => {
|
|
227
|
+
const ext = path.extname(file).toLowerCase().replace('.', '');
|
|
228
|
+
return IMAGE_ALLOWED_EXTENSIONS.includes(ext);
|
|
229
|
+
});
|
|
230
|
+
for (const file of files) {
|
|
231
|
+
const filePath = path.join(imagesDir, file);
|
|
232
|
+
const stat = fs.statSync(filePath);
|
|
233
|
+
if (stat.size > IMAGE_MAX_SIZE) {
|
|
234
|
+
loggerApi.warn(`Skipping ${file}: exceeds ${IMAGE_MAX_SIZE} bytes limit`);
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
const uploadUrl = `/webapi/cli/themes/${skinId}/skinstore/files`;
|
|
238
|
+
const result = await themeSkinstoreApi.uploadImage({
|
|
239
|
+
credentials,
|
|
240
|
+
uploadUrl,
|
|
241
|
+
imagePath: filePath
|
|
242
|
+
});
|
|
243
|
+
if (result?.isSuccess && result?.imageId) {
|
|
244
|
+
imageIds.push(result.imageId);
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
loggerApi.warn(`Failed to upload ${file}`, { details: result?.messages });
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return imageIds;
|
|
251
|
+
}
|
|
252
|
+
#renderPublishErrors(messages) {
|
|
253
|
+
if (!messages) {
|
|
254
|
+
renderOnce(React.createElement(ErrorBox, { header: "Publishing failed." },
|
|
255
|
+
React.createElement(Text, null, "An unknown error occurred.")));
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
renderOnce(React.createElement(ErrorBox, { header: "Publishing failed. Validation errors:" }, Object.entries(messages).map(([field, msg]) => (React.createElement(Text, { key: field },
|
|
259
|
+
field,
|
|
260
|
+
": ",
|
|
261
|
+
typeof msg === 'string' ? msg : Object.values(msg).join(', '))))));
|
|
262
|
+
}
|
|
80
263
|
}
|
|
@@ -10,10 +10,10 @@ export class ThemeSkinstoreApi extends FeatureApi {
|
|
|
10
10
|
async getPublishFormData(props) {
|
|
11
11
|
return this.#service.getPublishFormData(props);
|
|
12
12
|
}
|
|
13
|
-
async
|
|
14
|
-
|
|
13
|
+
async publishTheme(props) {
|
|
14
|
+
return this.#service.publishTheme(props);
|
|
15
15
|
}
|
|
16
|
-
async
|
|
17
|
-
|
|
16
|
+
async uploadImage(props) {
|
|
17
|
+
return this.#service.uploadImage(props);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -14,4 +14,30 @@ export class ThemeSkinstoreHttpApi {
|
|
|
14
14
|
isPrivate: true
|
|
15
15
|
});
|
|
16
16
|
}
|
|
17
|
+
publishTheme({ actionData, shopUrl, payload }) {
|
|
18
|
+
const { method, url } = actionData;
|
|
19
|
+
return this.#httpApi.fetch({
|
|
20
|
+
url: `${shopUrl}${url}`,
|
|
21
|
+
method,
|
|
22
|
+
data: payload,
|
|
23
|
+
sanitizeOptions: {
|
|
24
|
+
disable: true
|
|
25
|
+
},
|
|
26
|
+
isPrivate: true
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
uploadImage({ shopUrl, url, imageBuffer }) {
|
|
30
|
+
return this.#httpApi.fetch({
|
|
31
|
+
url: `${shopUrl}${url}`,
|
|
32
|
+
method: 'post',
|
|
33
|
+
data: imageBuffer,
|
|
34
|
+
headers: {
|
|
35
|
+
'Content-Type': 'application/octet-stream'
|
|
36
|
+
},
|
|
37
|
+
sanitizeOptions: {
|
|
38
|
+
disable: true
|
|
39
|
+
},
|
|
40
|
+
isPrivate: true
|
|
41
|
+
});
|
|
42
|
+
}
|
|
17
43
|
}
|
|
@@ -2,13 +2,18 @@ import { STATUS_CODES } from '@dreamcommerce/star_core';
|
|
|
2
2
|
import { HttpErrorsFactory } from '../../../../../cli/class/errors/http/http_errors_factory.js';
|
|
3
3
|
import { DownloadFileErrorsFactory } from '../../../../../utils/download_file/download_file_errors_factory.js';
|
|
4
4
|
import { toControls } from '../../../../../cli/features/controls/controls_dto_mappers.js';
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
const PUBLISH_RESPONSE_STATUSES = [STATUS_CODES.ok, STATUS_CODES.badRequest];
|
|
5
7
|
export class ThemeSkinstoreService {
|
|
6
8
|
#httpApi;
|
|
7
|
-
|
|
9
|
+
#logger;
|
|
10
|
+
constructor({ httpApi, logger }) {
|
|
8
11
|
this.#httpApi = httpApi;
|
|
12
|
+
this.#logger = logger;
|
|
9
13
|
}
|
|
10
14
|
async getPublishFormData({ credentials, actionData }) {
|
|
11
15
|
try {
|
|
16
|
+
this.#logger.info('Fetching publish form data');
|
|
12
17
|
const { response: request } = this.#httpApi.getPublishFormData({ actionData, shopUrl: credentials.shopUrl });
|
|
13
18
|
const response = await request;
|
|
14
19
|
if (response?.status !== STATUS_CODES.ok)
|
|
@@ -16,17 +21,64 @@ export class ThemeSkinstoreService {
|
|
|
16
21
|
return response?.data ? toControls(response.data) : [];
|
|
17
22
|
}
|
|
18
23
|
catch (err) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
24
|
+
this.#logger.error('Error fetching publish form data', { error: err });
|
|
25
|
+
this.#handleHttpError(err);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async publishTheme({ credentials, actionData, payload }) {
|
|
29
|
+
try {
|
|
30
|
+
this.#logger.info('Publishing theme', {
|
|
31
|
+
details: { actionData }
|
|
32
|
+
});
|
|
33
|
+
const { response: request } = this.#httpApi.publishTheme({
|
|
34
|
+
actionData,
|
|
35
|
+
shopUrl: credentials.shopUrl,
|
|
36
|
+
payload
|
|
37
|
+
});
|
|
38
|
+
const response = await request;
|
|
39
|
+
if (!PUBLISH_RESPONSE_STATUSES.includes(response?.status))
|
|
40
|
+
return;
|
|
41
|
+
this.#logger.info('Successfully published theme');
|
|
42
|
+
return response?.data;
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
this.#logger.error('Error publishing theme', { error: err });
|
|
46
|
+
this.#handleHttpError(err);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async uploadImage({ credentials, uploadUrl, imagePath }) {
|
|
50
|
+
try {
|
|
51
|
+
this.#logger.info('Uploading image', {
|
|
52
|
+
details: { uploadUrl, imagePath }
|
|
53
|
+
});
|
|
54
|
+
const imageBuffer = fs.readFileSync(imagePath);
|
|
55
|
+
const { response: request } = this.#httpApi.uploadImage({
|
|
56
|
+
shopUrl: credentials.shopUrl,
|
|
57
|
+
url: uploadUrl,
|
|
58
|
+
imageBuffer
|
|
59
|
+
});
|
|
60
|
+
const response = await request;
|
|
61
|
+
if (response?.status !== STATUS_CODES.ok)
|
|
62
|
+
return;
|
|
63
|
+
this.#logger.info('Successfully uploaded image');
|
|
64
|
+
return response?.data;
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
this.#logger.error('Error uploading image', { error: err });
|
|
68
|
+
this.#handleHttpError(err);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
#handleHttpError(err) {
|
|
72
|
+
//TODO to basic class
|
|
73
|
+
switch (err.response?.status) {
|
|
74
|
+
case 403:
|
|
75
|
+
throw HttpErrorsFactory.createForbiddenError();
|
|
76
|
+
case 401:
|
|
77
|
+
throw HttpErrorsFactory.createUnauthorizedError();
|
|
78
|
+
case 404:
|
|
79
|
+
throw HttpErrorsFactory.createNotFoundError();
|
|
80
|
+
default:
|
|
81
|
+
throw DownloadFileErrorsFactory.downloadError(err.response?.status);
|
|
30
82
|
}
|
|
31
83
|
}
|
|
32
84
|
}
|
|
@@ -2,3 +2,7 @@ export const THEME_SKINSTORE_LOCATION = 'skinstore';
|
|
|
2
2
|
export const THEME_SKINSTORE_SETTINGS_FILE_NAME = 'settings.json';
|
|
3
3
|
export const THEME_SKINSTORE_API_NAME = 'ThemeSkinstoreApi';
|
|
4
4
|
export const THEME_SKINSTORE_FEATURE_NAME = 'ThemeSkinstore';
|
|
5
|
+
export const RELEASE_TYPE_TEST = 0;
|
|
6
|
+
export const RELEASE_TYPE_STABLE = 1;
|
|
7
|
+
export const IMAGE_MAX_SIZE = 5242880;
|
|
8
|
+
export const IMAGE_ALLOWED_EXTENSIONS = ['gif', 'jpeg', 'jpg', 'png', 'webp'];
|
|
@@ -3,11 +3,16 @@ import { THEME_SKINSTORE_FEATURE_NAME } from './theme_publish_constants.js';
|
|
|
3
3
|
import { ThemeSkinstoreService } from './service/theme_skinstore_service.js';
|
|
4
4
|
import { ThemeSkinstoreHttpApi } from './http/theme_skinstore_http_api.js';
|
|
5
5
|
import { ThemeSkinstoreApi } from './api/theme_skinstore_api.js';
|
|
6
|
+
import { LOGGER_API_NAME } from '../../../../cli/utilities/features/logger/logger_constants.js';
|
|
6
7
|
export class ThemeSkinstoreInitializer extends SyncFeatureInitializer {
|
|
7
8
|
static featureName = THEME_SKINSTORE_FEATURE_NAME;
|
|
8
9
|
init() {
|
|
9
10
|
const httpApi = this.getApiSync(HTTP_REQUESTER_API_NAME);
|
|
10
|
-
const
|
|
11
|
+
const loggerApi = this.getApiSync(LOGGER_API_NAME);
|
|
12
|
+
const service = new ThemeSkinstoreService({
|
|
13
|
+
httpApi: new ThemeSkinstoreHttpApi(httpApi),
|
|
14
|
+
logger: loggerApi
|
|
15
|
+
});
|
|
11
16
|
return {
|
|
12
17
|
cores: [
|
|
13
18
|
{
|
package/build/theme/index.js
CHANGED
|
@@ -17,6 +17,7 @@ import { ThemeDeleteInitializer } from './features/theme/delete/theme_delete_ini
|
|
|
17
17
|
import { ThemeActionsInitializer } from './features/theme/actions/theme_actions_initializer.js';
|
|
18
18
|
import { ThemeWatchCommand } from './commands/watch/theme_watch_command.js';
|
|
19
19
|
import { ThemeWatchInitializer } from './features/theme/watch/theme_watch_initializer.js';
|
|
20
|
+
import { ThemeSkinstoreInitializer } from './features/theme/skinstore/theme_skinstore_initialzier.js';
|
|
20
21
|
export const COMMANDS = {
|
|
21
22
|
[THEME_COMMANDS_NAME.list]: ThemeListCommand,
|
|
22
23
|
[THEME_COMMANDS_NAME.pull]: ThemePullCommand,
|
|
@@ -34,6 +35,7 @@ export const COMMAND_TO_FEATURES_MAP = {
|
|
|
34
35
|
[THEME_COMMANDS_NAME.push]: [ThemeFetchInitializer, ThemePushInitializer],
|
|
35
36
|
[THEME_COMMANDS_NAME.verify]: ThemeVerifyInitializer,
|
|
36
37
|
[THEME_COMMANDS_NAME.delete]: ThemeDeleteInitializer,
|
|
38
|
+
[THEME_COMMANDS_NAME.publish]: ThemeSkinstoreInitializer,
|
|
37
39
|
[THEME_COMMANDS_NAME.watch]: [ThemeFetchInitializer, ThemePushInitializer, ThemeWatchInitializer]
|
|
38
40
|
};
|
|
39
41
|
export const getThemeInitializersForCommand = (commandName) => {
|
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.9.4-
|
|
5
|
+
"version": "0.9.4-3",
|
|
6
6
|
"description": "CLI tool for Shoper",
|
|
7
7
|
"author": "Joanna Firek",
|
|
8
8
|
"license": "MIT",
|
|
@@ -48,11 +48,9 @@
|
|
|
48
48
|
"chalk": "5.4.1",
|
|
49
49
|
"conf": "13.1.0",
|
|
50
50
|
"fast-glob": "3.3.3",
|
|
51
|
-
"figlet": "1.9.4",
|
|
52
51
|
"figures": "6.1.0",
|
|
53
52
|
"fs-extra": "11.3.0",
|
|
54
53
|
"fs-tree-diff": "2.0.1",
|
|
55
|
-
"ignore": "7.0.5",
|
|
56
54
|
"ink": "6.0.1",
|
|
57
55
|
"ink-link": "4.1.0",
|
|
58
56
|
"ink-gradient": "3.0.0",
|
|
@@ -79,6 +77,7 @@
|
|
|
79
77
|
"micromatch": "4.0.8",
|
|
80
78
|
"walk-sync": "3.0.0",
|
|
81
79
|
"yauzl": "3.2.0",
|
|
80
|
+
"figlet": "1.9.4",
|
|
82
81
|
"yazl": "3.3.1",
|
|
83
82
|
"puppeteer": "24.31.0",
|
|
84
83
|
"gradient-string": "3.0.0"
|