shoplazza-cli 1.0.7 → 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 (124) hide show
  1. package/README.md +83 -2
  2. package/bin/shoplazza +8 -15
  3. package/lib/app/api/index.js +96 -0
  4. package/lib/app/commands/build.js +101 -53
  5. package/lib/app/commands/connect.js +73 -0
  6. package/lib/app/commands/create.js +105 -0
  7. package/lib/app/commands/deploy.js +45 -208
  8. package/lib/app/commands/list.js +35 -0
  9. package/lib/app/commands/release.js +59 -0
  10. package/lib/app/commands/serve.js +172 -0
  11. package/lib/app/commands/versions.js +55 -0
  12. package/lib/app/index.js +22 -30
  13. package/lib/app/template/basic-app/README.md +125 -0
  14. package/lib/app/template/basic-app/extension.config.json +4 -0
  15. package/lib/app/template/basic-app/package.json +18 -0
  16. package/lib/app/template/basic-app/theme-app/assets/index.css +4 -0
  17. package/lib/app/template/basic-app/theme-app/assets-manifest.json +1 -0
  18. package/lib/app/template/basic-app/theme-app/blocks/index.liquid +16 -0
  19. package/lib/app/template/basic-app/theme-app/locales/ar-SA.json +1 -0
  20. package/lib/app/template/basic-app/theme-app/locales/de-DE.json +1 -0
  21. package/lib/app/template/basic-app/theme-app/locales/en-US.json +6 -0
  22. package/lib/app/template/basic-app/theme-app/locales/es-ES.json +1 -0
  23. package/lib/app/template/basic-app/theme-app/locales/fr-FR.json +1 -0
  24. package/lib/app/template/basic-app/theme-app/locales/id-ID.json +1 -0
  25. package/lib/app/template/basic-app/theme-app/locales/it-IT.json +1 -0
  26. package/lib/app/template/basic-app/theme-app/locales/ja-JP.json +1 -0
  27. package/lib/app/template/basic-app/theme-app/locales/ko-KR.json +1 -0
  28. package/lib/app/template/basic-app/theme-app/locales/nl-NL.json +1 -0
  29. package/lib/app/template/basic-app/theme-app/locales/pl-PL.json +1 -0
  30. package/lib/app/template/basic-app/theme-app/locales/pt-PT.json +1 -0
  31. package/lib/app/template/basic-app/theme-app/locales/ru-RU.json +1 -0
  32. package/lib/app/template/basic-app/theme-app/locales/th-TH.json +1 -0
  33. package/lib/app/template/basic-app/theme-app/locales/zh-CN.json +6 -0
  34. package/lib/app/template/basic-app/theme-app/locales/zh-TW.json +1 -0
  35. package/lib/app/template/basic-app/theme-app/snippets/index.liquid +8 -0
  36. package/lib/app/template/embed-app/README.md +125 -0
  37. package/lib/app/template/embed-app/extension.config.json +4 -0
  38. package/lib/app/template/embed-app/package.json +18 -0
  39. package/lib/app/template/embed-app/theme-app/assets-manifest.json +1 -0
  40. package/lib/app/template/embed-app/theme-app/blocks/index.liquid +18 -0
  41. package/lib/app/template/embed-app/theme-app/locales/ar-SA.json +1 -0
  42. package/lib/app/template/embed-app/theme-app/locales/de-DE.json +1 -0
  43. package/lib/app/template/embed-app/theme-app/locales/en-US.json +6 -0
  44. package/lib/app/template/embed-app/theme-app/locales/es-ES.json +1 -0
  45. package/lib/app/template/embed-app/theme-app/locales/fr-FR.json +1 -0
  46. package/lib/app/template/embed-app/theme-app/locales/id-ID.json +1 -0
  47. package/lib/app/template/embed-app/theme-app/locales/it-IT.json +1 -0
  48. package/lib/app/template/embed-app/theme-app/locales/ja-JP.json +1 -0
  49. package/lib/app/template/embed-app/theme-app/locales/ko-KR.json +1 -0
  50. package/lib/app/template/embed-app/theme-app/locales/nl-NL.json +1 -0
  51. package/lib/app/template/embed-app/theme-app/locales/pl-PL.json +1 -0
  52. package/lib/app/template/embed-app/theme-app/locales/pt-PT.json +1 -0
  53. package/lib/app/template/embed-app/theme-app/locales/ru-RU.json +1 -0
  54. package/lib/app/template/embed-app/theme-app/locales/th-TH.json +1 -0
  55. package/lib/app/template/embed-app/theme-app/locales/zh-CN.json +6 -0
  56. package/lib/app/template/embed-app/theme-app/locales/zh-TW.json +1 -0
  57. package/lib/app/template/embed-app/theme-app/snippets/index.liquid +8 -0
  58. package/lib/app/template/embed-app/theme-app/snippets/index_css.liquid +6 -0
  59. package/lib/app/utils/config.js +32 -0
  60. package/lib/app/utils/index.js +213 -0
  61. package/lib/auth/getCode.js +2 -2
  62. package/lib/auth/index.js +2 -2
  63. package/lib/check.js +28 -0
  64. package/lib/checkout/api.js +12 -36
  65. package/lib/checkout/build.js +1 -1
  66. package/lib/checkout/create.js +1 -1
  67. package/lib/checkout/deploy.js +1 -1
  68. package/lib/checkout/dev/index.js +1 -1
  69. package/lib/checkout/fields.js +1 -1
  70. package/lib/checkout/preview.js +1 -1
  71. package/lib/checkout/pull.js +1 -0
  72. package/lib/checkout/push.js +1 -1
  73. package/lib/checkout/undeploy.js +1 -1
  74. package/lib/checkout/util.js +1 -1
  75. package/lib/checkout/verify.js +1 -1
  76. package/lib/commands/login.js +1 -1
  77. package/lib/commands/logout.js +1 -1
  78. package/lib/commands/theme/delete.js +1 -1
  79. package/lib/commands/theme/package.js +1 -1
  80. package/lib/commands/theme/publish.js +1 -1
  81. package/lib/commands/theme/pull.js +1 -1
  82. package/lib/commands/theme/push.js +1 -1
  83. package/lib/commands/theme/serve.js +2 -2
  84. package/lib/{app → common}/login.js +1 -1
  85. package/lib/function/bin/index.js +20 -0
  86. package/lib/function/bin/javy/javy-arm-linux-v5.0.1 +0 -0
  87. package/lib/function/bin/javy/javy-arm-macos-v5.0.1 +0 -0
  88. package/lib/function/bin/javy/javy-x86_64-linux-v5.0.1 +0 -0
  89. package/lib/function/bin/javy/javy-x86_64-macos-v5.0.1 +0 -0
  90. package/lib/function/bin/javy/javy-x86_64-windows-v5.0.1 +0 -0
  91. package/lib/function/commands/compile.js +42 -0
  92. package/lib/function/commands/create.js +77 -0
  93. package/lib/function/commands/list.js +18 -0
  94. package/lib/function/commands/release.js +69 -0
  95. package/lib/function/index.js +24 -0
  96. package/lib/function/template/js/README.md +37 -0
  97. package/lib/function/template/js/_gitignore +4 -0
  98. package/lib/function/template/js/extension.config.json +5 -0
  99. package/lib/function/template/js/package.json +17 -0
  100. package/lib/function/template/js/src/index.js +64 -0
  101. package/lib/function/utils.js +29 -0
  102. package/lib/openAPI/api.js +1 -1
  103. package/lib/openAPI/index.js +21 -11
  104. package/lib/oss.js +99 -0
  105. package/lib/partner-api/axios.js +67 -0
  106. package/lib/partner-api/index.js +79 -0
  107. package/lib/{checkout → utils}/console.js +3 -2
  108. package/lib/utils/env.js +17 -0
  109. package/lib/utils/file.js +48 -0
  110. package/lib/utils/platform.js +37 -0
  111. package/lib/{utils.js → utils/utils.js} +52 -0
  112. package/package.json +2 -2
  113. package/lib/app/commands/generate.js +0 -50
  114. package/lib/app/commands/publish.js +0 -52
  115. package/lib/app/extensions/index.js +0 -13
  116. package/lib/app/extensions/theme-app.js +0 -103
  117. package/lib/app/inquirers/version.js +0 -131
  118. /package/lib/{app → common}/constants.js +0 -0
  119. /package/lib/{app → common}/db/partner.js +0 -0
  120. /package/lib/{app → common}/inquirers/choose-app.js +0 -0
  121. /package/lib/{app → common}/inquirers/choose-partner.js +0 -0
  122. /package/lib/{app → common}/log.js +0 -0
  123. /package/lib/{app → common}/logout.js +0 -0
  124. /package/lib/{config.js → utils/config.js} +0 -0
@@ -1,218 +1,55 @@
1
- const axios = require('axios');
2
- const ora = require('ora');
1
+ const inquirer = require('inquirer');
3
2
  const chalk = require('chalk');
4
- const fs = require('fs-extra');
5
- const SparkMD5 = require('spark-md5');
6
- const FormData = require('form-data');
7
- const path = require('path');
8
-
9
- const { PARNTER_URL } = require('../constants');
10
- const { getValue, PARTNER_KEYS, getApp, set } = require('../db/partner');
11
- const { getZipName } = require('./build');
12
- const { inputVersion } = require('../inquirers/version');
13
- const { line, done } = require('../log');
14
-
15
- const getZipPath = () => {
16
- const spinner = ora(chalk.cyan('Finding your built zip ...')).start();
17
- try {
18
- const zipName = getZipName();
19
- const filename = fs.readdirSync(process.cwd()).find((name) => {
20
- const extname = path.extname(name).replace('.', '');
21
- return extname === 'zip' && name.startsWith(zipName);
22
- });
23
-
24
- if (!filename) {
25
- throw new Error('not zip');
3
+ const ora = require('ora');
4
+ const { getThemeExtensionConfig } = require('../utils');
5
+ const { getThemeAppVersionList, toDeployThemeApp } = require('../api');
6
+
7
+ async function deployVersion(extensionId, versionInfo) {
8
+ await toDeployThemeApp({
9
+ extension_id: extensionId,
10
+ version_id: versionInfo.version_id,
11
+ type: 'enable'
12
+ });
13
+ console.log(chalk.green(`Version ${versionInfo.version} has been deployed successfully.`));
14
+ }
15
+
16
+ async function usePrompt(versionList) {
17
+ const choices = versionList.map((v) => ({
18
+ name: `${v.version} (${v.exts}) - ${v.created_at}`,
19
+ value: v.version_id
20
+ }));
21
+ return inquirer.prompt([
22
+ {
23
+ type: 'list',
24
+ name: 'selectedVersion',
25
+ message: 'Select a version to deploy:',
26
+ choices,
27
+ loop: false
26
28
  }
29
+ ]);
30
+ }
27
31
 
28
- const fileInfo = fs.statSync(`${process.cwd()}/${filename}`);
29
-
30
- spinner.succeed(
31
- chalk.cyan(
32
- `Success to find your zip: ${chalk.green(`${filename} ${(fileInfo.size / (1024 * 1024)).toFixed(2)}M`)}`
33
- )
34
- );
35
- return path.resolve(process.cwd(), filename);
36
- } catch (e) {
37
- spinner.fail(chalk.red('Failed to find your zip, be sure you have built app in root dir!'));
38
- }
39
- };
40
-
41
- const getBufferAndMd5 = async (filePath) => {
42
- const spinner = ora(chalk.cyan('Begin to read zip and generate md5 code ...')).start();
43
-
32
+ async function deploy() {
44
33
  try {
45
- return await new Promise((resolve, reject) => {
46
- const spark = new SparkMD5.ArrayBuffer();
47
- let buffers = [];
48
-
49
- const rs = fs.createReadStream(filePath, { autoClose: true });
50
- rs.on('data', (data) => {
51
- buffers.push(data);
52
- spark.append(data);
53
- });
54
-
55
- rs.on('end', () => {
56
- const md5 = spark.end();
57
- const completedBuffer = Buffer.concat(buffers);
58
- spinner.succeed(chalk.cyan('Success to analyse zip'));
59
- resolve([completedBuffer, md5 + '.zip']);
60
- });
61
-
62
- rs.on('error', (err) => {
63
- reject(err);
64
- });
65
- });
66
- } catch (e) {
67
- spinner.fail(chalk.red('Failed to analyse zip, please try again!'));
68
- }
69
- };
70
-
71
- const getSign = async () => {
72
- const spinner = ora(chalk.cyan('Waiting get file sign ...')).start();
73
-
74
- try {
75
- const app = getApp();
76
- const partnerId = getValue(PARTNER_KEYS.PARTNER_ID);
77
- const sessionId = getValue(PARTNER_KEYS.SESSION_ID);
78
-
79
- const url = `${PARNTER_URL}/api/partner/apps/${app.uid}/theme_extensions/file/signv2`;
80
- const res = await axios.get(url, {
81
- headers: {
82
- Cookie: `awesomev2=${sessionId}`,
83
- 'x-shoplazza-partner-id': partnerId
84
- }
85
- });
86
- spinner.succeed(chalk.cyan('Success to get file sign'));
87
- return res.data;
88
- } catch (e) {
89
- spinner.fail(chalk.red(e.message || e));
90
- }
91
- };
92
-
93
- const deployOss = async () => {
94
- const path = getZipPath();
95
- if (path) {
96
- const [buffer, md5] = await getBufferAndMd5(path);
97
- const signData = await getSign();
98
- if (!signData) {
99
- return;
34
+ const { extensionId } = await getThemeExtensionConfig();
35
+ if (!extensionId) {
36
+ throw new Error('ExtensionId is empty, please use `serve` command first.');
100
37
  }
101
-
102
- const spinner = ora(chalk.cyan('Deploying your zip to cdn ...')).start();
103
-
104
- try {
105
- const formData = new FormData();
106
- formData.append('policy', signData.policy);
107
- formData.append('OSSAccessKeyId', signData.access_id);
108
- formData.append('success_action_status', 200);
109
- formData.append('signature', signData.sign);
110
- formData.append('x-oss-forbid-overwrite', 'true');
111
- formData.append('key', md5);
112
- formData.append('file', buffer);
113
-
114
- const url = `https:${signData.write_host}/`;
115
- const res = await axios.post(url, formData, {
116
- global: true,
117
- maxContentLength: 100000000,
118
- maxBodyLength: 1000000000
119
- });
120
-
121
- if (res.status !== 200) {
122
- throw new Error(`${res.status} ${resstatusText}`);
123
- }
124
- spinner.succeed();
125
- return md5;
126
- } catch (e) {
127
- // 409 repeat filename
128
- if (e?.response?.status === 409) {
129
- spinner.succeed();
130
- return md5;
131
- }
132
- spinner.fail();
133
- console.log(chalk.red(e.message || e));
134
- }
135
- }
136
- };
137
-
138
- const deployPartner = async () => {
139
- const md5 = await deployOss();
140
- if (!md5) {
141
- return;
142
- }
143
-
144
- const spinner = ora(chalk.cyan('Deploying your zip to PARTNER ...')).start();
145
- try {
146
- const app = getApp();
147
- if (!app) {
148
- spinner.fail(chalk.red('Please choose your partner first!'));
149
- return;
38
+ const spinner = ora('Fetching version list...').start();
39
+ const res = await getThemeAppVersionList(extensionId);
40
+ const versionList = res.data?.data || [];
41
+ if (!versionList.length) {
42
+ spinner.succeed('Version list loaded.');
43
+ throw new Error('No version found, please use `build` command to upload a version first.');
150
44
  }
151
-
152
- const partnerId = getValue(PARTNER_KEYS.PARTNER_ID);
153
- const url = `${PARNTER_URL}/api/partner/apps/${app.uid}/theme_extensions`;
154
- const res = await axios.put(
155
- url,
156
- {
157
- title: getZipName(),
158
- name: getZipName(),
159
- file_name: md5
160
- },
161
- {
162
- headers: {
163
- cookie: `awesomev2=${getValue(PARTNER_KEYS.SESSION_ID)};`,
164
- 'x-shoplazza-partner-id': partnerId
165
- }
166
- }
167
- );
168
-
169
- set({ [PARTNER_KEYS.EXTENSION_ID]: res.data.extension_id });
170
- spinner.succeed();
171
- return true;
172
- } catch (e) {
173
- spinner.fail();
174
- console.log(e.message || e);
175
- console.log(chalk.red(JSON.stringify(e.response.data)));
45
+ spinner.succeed('Version list loaded.');
46
+ const { selectedVersion } = await usePrompt(versionList);
47
+ const versionInfo = versionList.find((v) => v.version_id === selectedVersion);
48
+ await deployVersion(extensionId, versionInfo);
49
+ } catch (error) {
50
+ console.error(chalk.red(`[ERROR IN DEPLOY] ${error.message}`));
176
51
  }
177
- };
178
-
179
- const createVersion = async (version) => {
180
- const spinner = ora(chalk.cyan('Creating your version task ...')).start();
181
-
182
- try {
183
- const app = getApp();
184
- const extensionId = getValue(PARTNER_KEYS.EXTENSION_ID);
185
- const partnerId = getValue(PARTNER_KEYS.PARTNER_ID);
186
-
187
- const url = `${PARNTER_URL}/api/partner/apps/${app.uid}/theme_extensions/${extensionId}/version_tasks`;
188
- await axios.post(
189
- url,
190
- {
191
- version
192
- },
193
- {
194
- headers: {
195
- cookie: `awesomev2=${getValue(PARTNER_KEYS.SESSION_ID)};`,
196
- 'x-shoplazza-partner-id': partnerId
197
- }
198
- }
199
- );
200
- spinner.succeed();
201
- return true;
202
- } catch (e) {
203
- spinner.fail();
204
- console.log(chalk.red(e.message || e));
205
- console.log(chalk.red(JSON.stringify(e.response?.data)));
206
- }
207
- };
208
-
209
- const deploy = async () => {
210
- line();
211
- ora(chalk.cyan('Deploy Begin')).succeed();
212
- let version;
213
- (await deployPartner()) && (version = await inputVersion()) && (await createVersion(version)) && done();
214
- line();
215
- };
52
+ }
216
53
 
217
54
  module.exports = {
218
55
  deploy
@@ -0,0 +1,35 @@
1
+ const chalk = require('chalk');
2
+ const ora = require('ora');
3
+ const { renderTable } = require('../utils');
4
+ const { getThemeAppList } = require('../api');
5
+
6
+ /**
7
+ * 控制台提示
8
+ */
9
+ function consoleTips(versionList) {
10
+ if (versionList.length) {
11
+ console.log(chalk.green(`\n📃 Your store has ${versionList.length} available theme extensions:`));
12
+ console.log(
13
+ renderTable(versionList, [
14
+ { label: 'App Name', filed: 'title' },
15
+ { label: 'CreateTime', filed: 'created_at', color: 'yellowBright' },
16
+ ])
17
+ );
18
+ } else {
19
+ console.log(chalk.green('Your store does not have any available theme extensions.'));
20
+ }
21
+ }
22
+
23
+ async function list() {
24
+ try {
25
+ const res = await getThemeAppList();
26
+ const themeAppList = res.data?.data || [];
27
+ consoleTips(themeAppList);
28
+ } catch (error) {
29
+ console.error(chalk.red(`[ERROR IN LIST] ${error.message}`));
30
+ }
31
+ }
32
+
33
+ module.exports = {
34
+ list
35
+ };
@@ -0,0 +1,59 @@
1
+ const inquirer = require('inquirer');
2
+ const chalk = require('chalk');
3
+ const ora = require('ora');
4
+ const { getThemeExtensionConfig } = require('../utils');
5
+ const { getThemeAppVersionList } = require('../api');
6
+ const { toReleaseApp } = require('../../partner-api/index');
7
+
8
+ async function releaseVersion(extensionId, versionInfo) {
9
+ const res = await toReleaseApp({
10
+ extensionId,
11
+ versionId: versionInfo.version_id
12
+ });
13
+ console.log(chalk.green(`Version ${versionInfo.version} has been released successfully.`));
14
+ }
15
+
16
+ async function usePrompt(versionList) {
17
+ const choices = versionList.map((v) => ({
18
+ name: `${v.version} (${v.exts}) - ${v.created_at}`,
19
+ value: v.version_id
20
+ }));
21
+ return inquirer.prompt([
22
+ {
23
+ type: 'list',
24
+ name: 'selectedVersion',
25
+ message: 'Select a version to release:',
26
+ choices,
27
+ loop: false
28
+ }
29
+ ]);
30
+ }
31
+
32
+ async function releaseToApp() {
33
+ try {
34
+ const { extensionId, appId } = await getThemeExtensionConfig();
35
+ if (!extensionId) {
36
+ throw new Error('ExtensionId is empty, please use `serve` command first.');
37
+ }
38
+ if (!appId) {
39
+ throw new Error('Missing appId, please use `connect` command first.');
40
+ }
41
+ const spinner = ora('Fetching version list...').start();
42
+ const res = await getThemeAppVersionList(extensionId);
43
+ const versionList = res.data?.data || [];
44
+ if (!versionList.length) {
45
+ spinner.succeed('Version list loaded.');
46
+ throw new Error('No version found, please use `build` command to upload a version first.');
47
+ }
48
+ spinner.succeed('Version list loaded.');
49
+ const { selectedVersion } = await usePrompt(versionList);
50
+ const versionInfo = versionList.find((v) => v.version_id === selectedVersion);
51
+ await releaseVersion(extensionId, versionInfo);
52
+ } catch (error) {
53
+ console.error(chalk.red(`[ERROR IN DEPLOY] ${error.message}`));
54
+ }
55
+ }
56
+
57
+ module.exports = {
58
+ release: releaseToApp
59
+ };
@@ -0,0 +1,172 @@
1
+ const chalk = require('chalk');
2
+ const inquirer = require('inquirer');
3
+ const fsExtra = require('fs-extra');
4
+ const ora = require('ora');
5
+ const { STORE_DOMAIN, THEME_APP_DIR_PATH, EXCHANGE_TOKEN } = require('../utils/config');
6
+ const { compress, getThemeExtensionConfig, setThemeExtensionConfig, getFileInfo } = require('../utils');
7
+ const {
8
+ toCreateThemeApp,
9
+ toUploadThemeApp,
10
+ getTaskStatus,
11
+ getThemeList,
12
+ toCreateFile,
13
+ toUpdateFile,
14
+ toDeleteFile
15
+ } = require('../api');
16
+ const { watchWorkspace } = require('../../utils/utils');
17
+ const { useOss } = require('../../oss');
18
+
19
+ /**
20
+ * 控制台提示信息
21
+ */
22
+ function consoleTips(selectedThemeId, extensionId) {
23
+ console.log(`\n======================================PREVIEW URLS======================================`);
24
+ console.log(chalk.cyan.bold('🔗 Admin Preview URL:'));
25
+ console.log(
26
+ chalk.blueBright(` https://${STORE_DOMAIN}/admin/card?theme_id=${selectedThemeId}&ext_debug=${extensionId}\n`)
27
+ );
28
+ console.log(chalk.cyan.bold('🔗 Storefront Preview URL:'));
29
+ console.log(chalk.blueBright(` https://${STORE_DOMAIN}?preview_theme_id=${selectedThemeId}&ext_debug=${extensionId}\n`));
30
+ console.log(`=====================================WATCHER RUNNING=====================================`);
31
+ console.log(chalk.green(`🎉 File watcher is now running!`));
32
+ console.log(chalk.green(`📂 Watching directory:`), chalk.blue(THEME_APP_DIR_PATH));
33
+ console.log(chalk.green(`✨ You can make changes to your files, and they will be processed automatically.`));
34
+ console.log(chalk.green(`🚀 Press Ctrl+C to stop.\n`));
35
+ }
36
+
37
+ /**
38
+ * 同步本地代码到远程服务器
39
+ */
40
+ async function syncLocalFiles(extensionId) {
41
+ const spinner = ora('Start synchronizing local files to remote...').start();
42
+ const { zipPath, zipName } = await compress(THEME_APP_DIR_PATH);
43
+ const { uploadOss } = useOss(
44
+ EXCHANGE_TOKEN,
45
+ STORE_DOMAIN,
46
+ `✗ No store found. Please run ${chalk.cyan('shoplazza login')} to login to a specific store.`
47
+ );
48
+ const zipOssUrl = await uploadOss(zipPath, zipName);
49
+ // 上传完成删除压缩包
50
+ fsExtra.removeSync(zipPath);
51
+ const res = await toUploadThemeApp(extensionId, {
52
+ resource_url: zipOssUrl
53
+ });
54
+ const taskId = res.data?.task_id;
55
+ if (!taskId) {
56
+ spinner.fail(chalk.red(`Failed to synchronize local files to remote location!`));
57
+ throw new Error('taskId is required');
58
+ }
59
+ // 轮询查看任务是否完成
60
+ return new Promise((resolve, reject) => {
61
+ const timer = setInterval(async () => {
62
+ const res = await getTaskStatus({ taskId });
63
+ if (res.data?.state === 1) {
64
+ clearInterval(timer);
65
+ spinner.succeed(chalk.green(`Successfully synchronized local files to remote location!`));
66
+ resolve();
67
+ } else if (res.data?.state === 2) {
68
+ clearInterval(timer);
69
+ spinner.fail(chalk.red(`Failed to synchronize local files to remote location!`));
70
+ reject(new Error(res.data?.message));
71
+ } else {
72
+ spinner.text = chalk.blue(`[WAITING] Synchronizing local files to remote...`);
73
+ }
74
+ }, 1000);
75
+ });
76
+ }
77
+
78
+ /**
79
+ * 交互选择预览主题
80
+ */
81
+ async function usePrompt() {
82
+ const res = await getThemeList();
83
+ const themeList = res.data?.data?.themes || [];
84
+ const { selectedThemeId } = await inquirer.prompt([
85
+ {
86
+ type: 'list',
87
+ name: 'selectedThemeId',
88
+ message: 'Please select a theme to preview:',
89
+ choices: themeList.map((theme) => ({
90
+ name: theme.name,
91
+ value: theme.id
92
+ })),
93
+ loop: false
94
+ }
95
+ ]);
96
+ return selectedThemeId;
97
+ }
98
+
99
+ /**
100
+ * 创建主题插件
101
+ */
102
+ async function createThemeApp(themeExtensionConfig) {
103
+ const data = {
104
+ title: themeExtensionConfig.extensionName || '' // 插件显示名称
105
+ };
106
+ if (themeExtensionConfig.extensionId) {
107
+ data.extension_id = themeExtensionConfig.extensionId;
108
+ }
109
+ const res = await toCreateThemeApp(data);
110
+ const extensionId = res.data?.extension_id;
111
+ await setThemeExtensionConfig({ extensionId });
112
+ return extensionId;
113
+ }
114
+
115
+ /**
116
+ * 启动监听
117
+ */
118
+ function startWatcher(extensionId) {
119
+ const ACTION_MAP = {
120
+ ADD: 'add',
121
+ CHANGE: 'change',
122
+ DELETE: 'delete'
123
+ };
124
+ const actionToApiMap = {
125
+ [ACTION_MAP.ADD]: toCreateFile,
126
+ [ACTION_MAP.CHANGE]: toUpdateFile,
127
+ [ACTION_MAP.DELETE]: toDeleteFile
128
+ };
129
+ const funcCache = {};
130
+ const handleFileChange = (action) => {
131
+ if (funcCache[action]) {
132
+ return funcCache[action];
133
+ }
134
+ const func = (filePath) => {
135
+ const { fileName, parentDirName } = getFileInfo(filePath);
136
+ const data = {
137
+ type: parentDirName,
138
+ location: fileName
139
+ };
140
+ if ([ACTION_MAP.CHANGE, ACTION_MAP.ADD].includes(action)) {
141
+ data.content = fsExtra.readFileSync(filePath, 'utf-8');
142
+ }
143
+ actionToApiMap[action](extensionId, data);
144
+ };
145
+ funcCache[action] = func;
146
+ return func;
147
+ };
148
+ watchWorkspace(THEME_APP_DIR_PATH, {
149
+ onAdd: handleFileChange(ACTION_MAP.ADD),
150
+ onChange: handleFileChange(ACTION_MAP.CHANGE),
151
+ onDelete: handleFileChange(ACTION_MAP.DELETE),
152
+ ignored: '**/assets-manifest.json',
153
+ });
154
+ }
155
+
156
+ async function serve() {
157
+ try {
158
+ const themeExtensionConfig = await getThemeExtensionConfig();
159
+ let extensionId = themeExtensionConfig.extensionId;
160
+ if (!extensionId) {
161
+ extensionId = await createThemeApp(themeExtensionConfig);
162
+ }
163
+ await syncLocalFiles(extensionId);
164
+ const selectedThemeId = await usePrompt();
165
+ startWatcher(extensionId);
166
+ consoleTips(selectedThemeId, extensionId);
167
+ } catch (error) {
168
+ console.error(chalk.red(`[ERROR IN SERVE] ${error.message}`));
169
+ }
170
+ }
171
+
172
+ module.exports = { serve };
@@ -0,0 +1,55 @@
1
+ const chalk = require('chalk');
2
+ const { getThemeExtensionConfig, renderTable } = require('../utils');
3
+ const { getThemeAppVersionList } = require('../api');
4
+
5
+ /**
6
+ * 控制台提示
7
+ */
8
+ function consoleTips(versionList) {
9
+ if (versionList.length) {
10
+ const tempVersionList = versionList.map((item) => ({
11
+ ...item,
12
+ composeVersion: item.published === 1 ? `${item.version}(published)` : item.version
13
+ }));
14
+ console.log(chalk.green('\n📜 Available Versions:'));
15
+ console.log(
16
+ renderTable(tempVersionList, [
17
+ {
18
+ label: 'Version',
19
+ filed: 'composeVersion',
20
+ color: 'yellowBright'
21
+ },
22
+ {
23
+ label: 'CreateTime',
24
+ filed: 'created_at',
25
+ color: 'blackBright'
26
+ },
27
+ {
28
+ label: 'Description',
29
+ filed: 'exts',
30
+ color: 'whiteBright'
31
+ }
32
+ ])
33
+ );
34
+ } else {
35
+ console.log(chalk.green('Your current theme extension does not have an available version.'));
36
+ }
37
+ }
38
+
39
+ async function versions() {
40
+ try {
41
+ const { extensionId } = await getThemeExtensionConfig();
42
+ if (!extensionId) {
43
+ throw new Error('ExtensionId is empty, please use `serve` command first.');
44
+ }
45
+ const res = await getThemeAppVersionList(extensionId);
46
+ const versionList = res.data?.data || [];
47
+ consoleTips(versionList);
48
+ } catch (error) {
49
+ console.error(chalk.red(`[ERROR IN VERSIONS] ${error.message}`));
50
+ }
51
+ }
52
+
53
+ module.exports = {
54
+ versions
55
+ };
package/lib/app/index.js CHANGED
@@ -1,37 +1,29 @@
1
- const { checkAndLogin } = require('./login');
2
- const { build } = require('./commands/build');
3
- const { deploy } = require('./commands/deploy');
4
- const { generate } = require('./commands/generate');
5
- const { publish } = require('./commands/publish');
6
- const { choosePartner } = require('./inquirers/choose-partner');
7
- const { chooseApp } = require('./inquirers/choose-app');
8
-
9
- const generateExtension = async () => {
10
- (await checkAndLogin()) && (await generate());
11
- };
1
+ function initThemeAppCommand(_program) {
2
+ const program = _program.command('te').alias('theme_extension').description('Shoplazza theme extension CLI');
12
3
 
13
- const deployExtension = async () => {
14
- (await checkAndLogin()) && (await deploy());
15
- };
4
+ program.command('create').description('Create a new theme extension').action(require('./commands/create').create);
16
5
 
17
- const publishExtension = async () => {
18
- (await checkAndLogin()) && (await publish());
19
- };
6
+ program
7
+ .command('serve')
8
+ .description('Start a local development server for the theme extension')
9
+ .action(require('./commands/serve').serve);
20
10
 
21
- const retry = async (options) => {
22
- if (options.partner) {
23
- (await checkAndLogin()) && (await choosePartner()) && (await chooseApp());
24
- }
11
+ program.command('build').description('Build the theme extension for production').action(require('./commands/build').build);
25
12
 
26
- if (options.app) {
27
- (await checkAndLogin()) && (await chooseApp());
28
- }
29
- };
13
+ program
14
+ .command('versions')
15
+ .description('List all versions of the theme extension')
16
+ .action(require('./commands/versions').versions);
17
+
18
+ program.command('deploy').description('Deploy the theme extension').action(require('./commands/deploy').deploy);
19
+
20
+ program.command('list').description('List all theme extensions').action(require('./commands/list').list);
21
+
22
+ program.command('connect').description('Establish a connection between the theme extension and the shoplazza app').action(require('./commands/connect').connect);
23
+
24
+ program.command('release').description('Release a theme extension version to be applied in the shoplazza app').action(require('./commands/release').release);
25
+ }
30
26
 
31
27
  module.exports = {
32
- generateExtension,
33
- deployExtension,
34
- publishExtension,
35
- buildExtension: build,
36
- retry
28
+ initThemeAppCommand
37
29
  };