shoplazza-cli 1.0.6 → 1.0.7-beta.2

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 (116) hide show
  1. package/bin/shoplazza +5 -1
  2. package/lib/app/api/index.js +96 -0
  3. package/lib/app/commands/build.js +63 -36
  4. package/lib/app/commands/connect.js +73 -0
  5. package/lib/app/commands/create.js +15 -14
  6. package/lib/app/commands/deploy.js +22 -14
  7. package/lib/app/commands/list.js +15 -11
  8. package/lib/app/commands/release.js +59 -0
  9. package/lib/app/commands/serve.js +105 -51
  10. package/lib/app/commands/versions.js +36 -25
  11. package/lib/app/index.js +11 -7
  12. package/lib/app/template/basic-app/README.md +19 -5
  13. package/lib/app/template/basic-app/extension.config.json +4 -0
  14. package/lib/app/template/basic-app/package.json +6 -5
  15. package/lib/app/template/basic-app/theme-app/assets/index.css +2 -2
  16. package/lib/app/template/basic-app/theme-app/assets-manifest.json +1 -0
  17. package/lib/app/template/basic-app/theme-app/blocks/index.liquid +6 -4
  18. package/lib/app/template/basic-app/theme-app/locales/ar-SA.json +1 -0
  19. package/lib/app/template/basic-app/theme-app/locales/de-DE.json +1 -0
  20. package/lib/app/template/basic-app/theme-app/locales/en-US.json +6 -0
  21. package/lib/app/template/basic-app/theme-app/locales/es-ES.json +1 -0
  22. package/lib/app/template/basic-app/theme-app/locales/fr-FR.json +1 -0
  23. package/lib/app/template/basic-app/theme-app/locales/id-ID.json +1 -0
  24. package/lib/app/template/basic-app/theme-app/locales/it-IT.json +1 -0
  25. package/lib/app/template/basic-app/theme-app/locales/ja-JP.json +1 -0
  26. package/lib/app/template/basic-app/theme-app/locales/ko-KR.json +1 -0
  27. package/lib/app/template/basic-app/theme-app/locales/nl-NL.json +1 -0
  28. package/lib/app/template/basic-app/theme-app/locales/pl-PL.json +1 -0
  29. package/lib/app/template/basic-app/theme-app/locales/pt-PT.json +1 -0
  30. package/lib/app/template/basic-app/theme-app/locales/ru-RU.json +1 -0
  31. package/lib/app/template/basic-app/theme-app/locales/th-TH.json +1 -0
  32. package/lib/app/template/basic-app/theme-app/locales/zh-CN.json +6 -0
  33. package/lib/app/template/basic-app/theme-app/locales/zh-TW.json +1 -0
  34. package/lib/app/template/basic-app/theme-app/snippets/index.liquid +1 -1
  35. package/lib/app/template/embed-app/README.md +19 -6
  36. package/lib/app/template/embed-app/extension.config.json +4 -0
  37. package/lib/app/template/embed-app/package.json +6 -5
  38. package/lib/app/template/embed-app/theme-app/assets-manifest.json +1 -0
  39. package/lib/app/template/embed-app/theme-app/blocks/index.liquid +7 -4
  40. package/lib/app/template/embed-app/theme-app/locales/ar-SA.json +1 -3
  41. package/lib/app/template/embed-app/theme-app/locales/de-DE.json +1 -3
  42. package/lib/app/template/embed-app/theme-app/locales/en-US.json +4 -1
  43. package/lib/app/template/embed-app/theme-app/locales/es-ES.json +1 -3
  44. package/lib/app/template/embed-app/theme-app/locales/fr-FR.json +1 -3
  45. package/lib/app/template/embed-app/theme-app/locales/id-ID.json +1 -3
  46. package/lib/app/template/embed-app/theme-app/locales/it-IT.json +1 -3
  47. package/lib/app/template/embed-app/theme-app/locales/ja-JP.json +1 -3
  48. package/lib/app/template/embed-app/theme-app/locales/ko-KR.json +1 -3
  49. package/lib/app/template/embed-app/theme-app/locales/nl-NL.json +1 -3
  50. package/lib/app/template/embed-app/theme-app/locales/pl-PL.json +1 -3
  51. package/lib/app/template/embed-app/theme-app/locales/pt-PT.json +1 -3
  52. package/lib/app/template/embed-app/theme-app/locales/ru-RU.json +1 -3
  53. package/lib/app/template/embed-app/theme-app/locales/th-TH.json +1 -3
  54. package/lib/app/template/embed-app/theme-app/locales/zh-CN.json +4 -1
  55. package/lib/app/template/embed-app/theme-app/locales/zh-TW.json +1 -3
  56. package/lib/app/template/embed-app/theme-app/snippets/index.liquid +1 -1
  57. package/lib/app/template/embed-app/theme-app/snippets/index_css.liquid +6 -0
  58. package/lib/app/utils/config.js +7 -4
  59. package/lib/app/utils/index.js +16 -23
  60. package/lib/auth/getCode.js +2 -2
  61. package/lib/auth/index.js +2 -2
  62. package/lib/check.js +26 -0
  63. package/lib/checkout/api.js +1 -2
  64. package/lib/checkout/build.js +1 -1
  65. package/lib/checkout/create.js +1 -1
  66. package/lib/checkout/deploy.js +1 -1
  67. package/lib/checkout/dev/index.js +1 -1
  68. package/lib/checkout/fields.js +1 -1
  69. package/lib/checkout/preview.js +1 -1
  70. package/lib/checkout/push.js +1 -1
  71. package/lib/checkout/undeploy.js +1 -1
  72. package/lib/checkout/util.js +1 -1
  73. package/lib/checkout/verify.js +1 -1
  74. package/lib/commands/theme/delete.js +1 -1
  75. package/lib/commands/theme/package.js +1 -1
  76. package/lib/commands/theme/publish.js +1 -1
  77. package/lib/commands/theme/pull.js +1 -1
  78. package/lib/commands/theme/push.js +1 -1
  79. package/lib/commands/theme/serve.js +2 -2
  80. package/lib/common/login.js +1 -1
  81. package/lib/function/bin/index.js +20 -0
  82. package/lib/function/bin/javy/javy-arm-linux-v5.0.1 +0 -0
  83. package/lib/function/bin/javy/javy-arm-macos-v5.0.1 +0 -0
  84. package/lib/function/bin/javy/javy-x86_64-linux-v5.0.1 +0 -0
  85. package/lib/function/bin/javy/javy-x86_64-macos-v5.0.1 +0 -0
  86. package/lib/function/bin/javy/javy-x86_64-windows-v5.0.1 +0 -0
  87. package/lib/function/commands/compile.js +42 -0
  88. package/lib/function/commands/create.js +77 -0
  89. package/lib/function/commands/list.js +18 -0
  90. package/lib/function/commands/release.js +69 -0
  91. package/lib/function/index.js +24 -0
  92. package/lib/function/template/js/README.md +37 -0
  93. package/lib/function/template/js/_gitignore +4 -0
  94. package/lib/function/template/js/extension.config.json +5 -0
  95. package/lib/function/template/js/package.json +17 -0
  96. package/lib/function/template/js/src/index.js +64 -0
  97. package/lib/function/utils.js +29 -0
  98. package/lib/openAPI/api.js +1 -1
  99. package/lib/openAPI/index.js +0 -1
  100. package/lib/oss.js +0 -3
  101. package/lib/partner-api/axios.js +67 -0
  102. package/lib/partner-api/index.js +79 -0
  103. package/lib/{checkout → utils}/console.js +3 -2
  104. package/lib/utils/env.js +17 -0
  105. package/lib/utils/file.js +48 -0
  106. package/lib/utils/platform.js +37 -0
  107. package/lib/{utils.js → utils/utils.js} +3 -3
  108. package/package.json +1 -1
  109. package/lib/app/api/api.js +0 -93
  110. package/lib/app/api/request.js +0 -72
  111. package/lib/app/template/basic-app/.ci/k8s.yaml +0 -4
  112. package/lib/app/template/basic-app/theme-app.config.json +0 -4
  113. package/lib/app/template/embed-app/.ci/k8s.yaml +0 -4
  114. package/lib/app/template/embed-app/theme-app/assets/index.css +0 -4
  115. package/lib/app/template/embed-app/theme-app.config.json +0 -4
  116. /package/lib/{config.js → utils/config.js} +0 -0
package/bin/shoplazza CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  process.noDeprecation = true; // 全局禁用废弃警告
4
+ require('../lib/check');
4
5
  const { program } = require('commander');
5
6
  const updateNotifier = require('update-notifier');
6
7
  const Sentry = require('@sentry/node');
@@ -11,6 +12,7 @@ require('../lib/tracing');
11
12
 
12
13
  const { makeCheckoutCommand } = require('../lib/checkout');
13
14
  const { initThemeAppCommand } = require('../lib/app');
15
+ const { makeFunctionCommand } = require('../lib/function');
14
16
 
15
17
  Sentry.init({
16
18
  dsn: 'https://89964605acaf4db8839f2d5237396d6c@sentry.shoplazza.com/730',
@@ -29,6 +31,7 @@ updateNotifier({ pkg }).notify({
29
31
  isGlobal: true
30
32
  });
31
33
  program.usage('[command] [options]');
34
+ program.option('--debug <ent>', 'debug mode')
32
35
 
33
36
  program.command('version').description('Welcome to the Shoplazza CLI').action(require('../lib/commands/version'));
34
37
  program.description('Welcome to the Shoplazza CLI').option('-v --version').action(require('../lib/commands/version'));
@@ -112,11 +115,12 @@ theme
112
115
  .option('-t, --theme <theme>', 'The ID of the theme that you want to delete.')
113
116
  .action(require('../lib/commands/theme/delete'));
114
117
 
115
-
116
118
  // checkout cli
117
119
  makeCheckoutCommand(program);
118
120
  // theme app cli
119
121
  initThemeAppCommand(program);
122
+ // function cli
123
+ makeFunctionCommand(program);
120
124
 
121
125
  program.parse(process.argv);
122
126
  !program.args.length && program.help();
@@ -0,0 +1,96 @@
1
+ const instance = require('../../openAPI/index');
2
+ const request = require('../../partner-api/axios');
3
+
4
+ /**
5
+ * 获取主题列表
6
+ */
7
+ async function getThemeList() {
8
+ return instance.get('/themes');
9
+ }
10
+
11
+ /**
12
+ * 获取店铺私有主题插件列表
13
+ * @returns
14
+ */
15
+ async function getThemeAppList() {
16
+ return instance.get('/theme-extensions');
17
+ }
18
+
19
+ /**
20
+ * 创建主题插件 or 更新主题插件信息
21
+ */
22
+ async function toCreateThemeApp(data) {
23
+ return instance.put('/theme-extensions', data);
24
+ }
25
+
26
+ /**
27
+ * 上传主题插件
28
+ */
29
+ async function toUploadThemeApp(extension_id, data) {
30
+ return instance.patch(`/theme-extensions/${extension_id}/dev-doctree`, data);
31
+ }
32
+
33
+ /**
34
+ * 新增文件
35
+ */
36
+ async function toCreateFile(extension_id, data) {
37
+ return instance.post(`/theme-extensions/${extension_id}/dev-doc`, data);
38
+ }
39
+
40
+ /**
41
+ * 更新文件
42
+ */
43
+ async function toUpdateFile(extension_id, data) {
44
+ return instance.patch(`/theme-extensions/${extension_id}/dev-doc`, data);
45
+ }
46
+
47
+ /**
48
+ * 删除文件
49
+ */
50
+ async function toDeleteFile(extension_id, params) {
51
+ return instance.delete(`/theme-extensions/${extension_id}/dev-doc`, {
52
+ params
53
+ });
54
+ }
55
+
56
+ /**
57
+ * 获取任务状态
58
+ */
59
+ async function getTaskStatus(data) {
60
+ return instance.get(`/theme-extensions/version-tasks/${data.taskId}`);
61
+ }
62
+
63
+ /**
64
+ * 获取主题插件版本列表
65
+ */
66
+ async function getThemeAppVersionList(extension_id) {
67
+ return instance.get(`/theme-extensions/${extension_id}/versions`);
68
+ }
69
+
70
+ /**
71
+ * 创建主题插件版本
72
+ */
73
+ async function toCreateThemeAppVersion(data) {
74
+ return instance.post(`/theme-extensions/version-tasks`, data);
75
+ }
76
+
77
+ /**
78
+ * 部署主题插件
79
+ */
80
+ async function toDeployThemeApp(data) {
81
+ return instance.post(`/theme-extensions/publications`, data);
82
+ }
83
+
84
+ module.exports = {
85
+ getThemeList,
86
+ getThemeAppList,
87
+ toCreateThemeApp,
88
+ toCreateFile,
89
+ toUpdateFile,
90
+ toDeleteFile,
91
+ toUploadThemeApp,
92
+ getThemeAppVersionList,
93
+ toCreateThemeAppVersion,
94
+ toDeployThemeApp,
95
+ getTaskStatus,
96
+ };
@@ -1,59 +1,83 @@
1
1
  const chalk = require('chalk');
2
2
  const inquirer = require('inquirer');
3
- const path = require('path');
4
- const { getThemeAppConfig, compareVersions } = require('../utils');
5
- const { getThemeAppVersionList, toCreateThemeAppVersion } = require('../api/api');
3
+ const ora = require('ora');
4
+ const fsExtra = require('fs-extra');
5
+ const { getThemeExtensionConfig, compareVersions, compress } = require('../utils');
6
+ const { THEME_APP_DIR_PATH, EXCHANGE_TOKEN, STORE_DOMAIN } = require('../utils/config');
7
+ const { getThemeAppVersionList, toCreateThemeAppVersion, getTaskStatus } = require('../api');
8
+ const { useOss } = require('../../oss');
6
9
 
7
- async function createNewVersion(appId, version, description) {
8
- const themeAppPath = path.resolve(WORKSPACE_PATH, 'theme-app');
9
- const { zipPath, zipName } = await compress(themeAppPath);
10
+ async function createNewVersion(extensionId, version, description) {
11
+ const spinner = ora('Start building a new version...').start();
12
+ const { zipPath, zipName } = await compress(THEME_APP_DIR_PATH);
13
+ const { uploadOss } = useOss(
14
+ EXCHANGE_TOKEN,
15
+ STORE_DOMAIN,
16
+ `✗ No store found. Please run ${chalk.cyan('shoplazza login')} to login to a specific store.`
17
+ );
10
18
  const zipOssUrl = await uploadOss(zipPath, zipName);
11
- const taskId = await toCreateThemeAppVersion({
12
- extension_id: appId,
19
+ // 上传完成删除压缩包
20
+ fsExtra.removeSync(zipPath);
21
+ const res = await toCreateThemeAppVersion({
22
+ extension_id: extensionId,
13
23
  version,
14
- description,
24
+ exts: description,
15
25
  resource_url: zipOssUrl
16
26
  });
17
- while (true) {
18
- const res = await getTaskStatus({ taskId });
19
- if (res.data?.task?.state === 1) {
20
- console.log(chalk.green(`[SUCCESS] Theme app pushed successfully.`));
21
- break;
22
- } else if (res.data?.task?.state === 2) {
23
- console.error(chalk.red(`[ERROR] Theme app push failed: ${res.data?.task?.error_message}`));
24
- break;
25
- } else {
26
- console.log(chalk.yellow(`[WAITING] Theme app push in progress...`));
27
- await new Promise((resolve) => setTimeout(resolve, 1000));
28
- }
27
+ const taskId = res.data?.task_id;
28
+
29
+ if (!taskId) {
30
+ spinner.fail(chalk.red(`Failed to build a new version!`));
31
+ throw new Error('taskId is required');
29
32
  }
33
+ return new Promise((resolve, reject) => {
34
+ const timer = setInterval(async () => {
35
+ const res = await getTaskStatus({ taskId });
36
+ if (res.data?.state === 1) {
37
+ clearInterval(timer);
38
+ spinner.succeed(chalk.green(`Successfully build a new version(v${version})!`));
39
+ resolve();
40
+ } else if (res.data?.state === 2) {
41
+ clearInterval(timer);
42
+ spinner.fail(chalk.red(`Failed to build a new version!`));
43
+ reject(new Error(res.data?.message));
44
+ } else {
45
+ spinner.text = chalk.blue(`[WAITING] Building a new version...`);
46
+ }
47
+ }, 1000);
48
+ });
30
49
  }
31
50
 
32
51
  /**
33
52
  * 交互式命令行
34
53
  */
35
- async function usePrompt() {
36
- const versionList = await getThemeAppVersionList();
37
- const latestVersion = versionList[versionList.length - 1];
54
+ async function usePrompt(extensionId) {
55
+ const res = await getThemeAppVersionList(extensionId);
38
56
 
39
- console.log(
40
- chalk.cyanBright(`\n🔍 Latest version: `) +
41
- chalk.yellow(`${latestVersion.version} `) +
42
- chalk.white(`(${latestVersion.description})`) +
43
- chalk.gray(` [Released on: ${latestVersion.date}]`)
44
- );
57
+ const latestVersion = res.data?.data?.[0];
58
+
59
+ if (latestVersion) {
60
+ console.log(
61
+ chalk.cyanBright(`\n🔍 Latest version: `) +
62
+ chalk.yellow(`${latestVersion.version} `) +
63
+ chalk.white(`(${latestVersion.description})`) +
64
+ chalk.gray(` [Released on: ${latestVersion.created_at}]`)
65
+ );
66
+ }
45
67
 
46
68
  return inquirer.prompt([
47
69
  {
48
70
  type: 'input',
49
71
  name: 'newVersion',
50
- message: 'Enter the new version number:',
72
+ message: 'Enter the new version number(e.g., 1.0.0):',
51
73
  validate: (newVersion) => {
52
74
  if (!/^[0-9]+\.[0-9]+\.[0-9]+$/.test(newVersion)) {
53
75
  return chalk.red('❌ Version must follow the format X.Y.Z (e.g., 1.0.0).');
54
76
  }
55
- if (compareVersions(newVersion, latestVersion.version) !== 1) {
56
- return chalk.red('❌ Version must be greater than the latest version.');
77
+ if (latestVersion) {
78
+ if (compareVersions(newVersion, latestVersion.version) !== 1) {
79
+ return chalk.red('❌ Version must be greater than the latest version.');
80
+ }
57
81
  }
58
82
  return true;
59
83
  }
@@ -74,9 +98,12 @@ async function usePrompt() {
74
98
 
75
99
  async function build() {
76
100
  try {
77
- const { appId } = await getThemeAppConfig();
78
- const { newVersion, description } = await usePrompt();
79
- await createNewVersion(appId, newVersion, description);
101
+ const { extensionId } = await getThemeExtensionConfig();
102
+ if (!extensionId) {
103
+ throw new Error('ExtensionId is empty, please use `serve` command first.');
104
+ }
105
+ const { newVersion, description } = await usePrompt(extensionId);
106
+ await createNewVersion(extensionId, newVersion, description);
80
107
  } catch (error) {
81
108
  console.error(chalk.red(`[ERROR IN BUILD] ${error.message}`));
82
109
  }
@@ -0,0 +1,73 @@
1
+ const chalk = require('chalk');
2
+ const inquirer = require('inquirer');
3
+ const { getThemeExtensionConfig, setThemeExtensionConfig } = require('../utils');
4
+ const { toConnectApp } = require('../../partner-api/index');
5
+
6
+ /**
7
+ * 交互式命令行
8
+ */
9
+ async function usePrompt() {
10
+ return await inquirer.prompt([
11
+ {
12
+ type: 'input',
13
+ name: 'clientId',
14
+ message: 'Please enter the shoplazza app Client ID:',
15
+ prefix: '*',
16
+ validate: (clientId) => {
17
+ if (!clientId.trim()) {
18
+ return 'Client ID cannot be empty';
19
+ }
20
+ return true;
21
+ }
22
+ },
23
+ {
24
+ type: 'input',
25
+ name: 'clientSecret',
26
+ message: 'Please enter the shoplazza app Client Secret:',
27
+ prefix: '*',
28
+ validate: (clientSecret) => {
29
+ if (!clientSecret.trim()) {
30
+ return 'Client Secret cannot be empty';
31
+ }
32
+ return true;
33
+ }
34
+ }
35
+ ]);
36
+ }
37
+
38
+ async function connectToApp() {
39
+ try {
40
+ let { extensionId, appId, accessToken } = await getThemeExtensionConfig();
41
+ if (!extensionId) {
42
+ throw new Error('ExtensionId is empty, please use `serve` command first.');
43
+ }
44
+
45
+ if (!accessToken) {
46
+ const result = await usePrompt();
47
+ appId = result.clientId;
48
+ appSecret = result.clientSecret;
49
+ await setThemeExtensionConfig({
50
+ appId,
51
+ appSecret
52
+ });
53
+ }
54
+
55
+ const res = await toConnectApp({
56
+ extensionId,
57
+ appId
58
+ });
59
+
60
+ if (+res.data?.code === 200) {
61
+ console.log(chalk.green('Connected to the Shoplazza app successfully!'));
62
+ console.log(chalk.cyan('You can use the `release` command to release a specific version to the Shoplazza app.'));
63
+ } else if (+res.data?.code === 400) {
64
+ console.log(chalk.green(res.data?.message));
65
+ }
66
+ } catch (error) {
67
+ console.error(chalk.red(`[ERROR IN CONNECT] ${error.message}`));
68
+ }
69
+ }
70
+
71
+ module.exports = {
72
+ connect: connectToApp
73
+ };
@@ -13,14 +13,14 @@ async function usePrompt() {
13
13
  {
14
14
  type: 'list',
15
15
  name: 'themeAppType',
16
- message: 'Select theme app type:',
16
+ message: 'Select theme extension type:',
17
17
  choices: [THEME_APP_TYPE.BASIC_APP.description, THEME_APP_TYPE.EMBEDS_APP.description],
18
18
  prefix: '*'
19
19
  },
20
20
  {
21
21
  type: 'input',
22
22
  name: 'projectName',
23
- message: 'Please enter the theme app project name:',
23
+ message: 'Please enter the theme extension project name:',
24
24
  prefix: '*',
25
25
  validate: (projectName) => {
26
26
  if (!projectName.trim()) {
@@ -35,12 +35,12 @@ async function usePrompt() {
35
35
  /**
36
36
  * 初始化项目
37
37
  */
38
- async function initProj(projectPath, projectName) {
38
+ async function initProj(projectPath, projectName, isBasicApp = false) {
39
39
  // 替换占位符 key文件相对路径 value替换的内容
40
40
  const replacementConfig = {
41
41
  'package.json': { projectName },
42
42
  'theme-app/blocks/index.liquid': { projectName },
43
- 'theme-app.config.json': { projectName }
43
+ 'extension.config.json': { projectName }
44
44
  };
45
45
  for (const [filePath, replacements] of Object.entries(replacementConfig)) {
46
46
  const fullPath = path.resolve(projectPath, filePath);
@@ -48,10 +48,14 @@ async function initProj(projectPath, projectName) {
48
48
  }
49
49
 
50
50
  // 重命名文件
51
- const filesToRename = ['assets/index.css', 'blocks/index.liquid', 'snippets/index.liquid'];
51
+ const filesToRename = [
52
+ isBasicApp ? 'assets/index.css' : 'snippets/index_css.liquid',
53
+ 'blocks/index.liquid',
54
+ 'snippets/index.liquid'
55
+ ];
52
56
  for (const file of filesToRename) {
53
57
  const filePath = path.resolve(projectPath, 'theme-app', file);
54
- await renameFile(filePath, `${projectName}${file.includes('snippets') ? '_snippet' : ''}`);
58
+ await renameFile(filePath, `${projectName}${filePath.includes('_css') ? '_css' : ''}`);
55
59
  }
56
60
  }
57
61
 
@@ -59,7 +63,7 @@ async function initProj(projectPath, projectName) {
59
63
  * 控制台提示信息
60
64
  */
61
65
  function consoleTips(projectName) {
62
- console.log(chalk.green(`Theme app project "${projectName}" has been successfully created.`));
66
+ console.log(chalk.green(`Theme extension project "${projectName}" has been successfully created.`));
63
67
  console.log(chalk.bold(`To get started:\n`));
64
68
  console.log(` ${chalk.cyan(`cd ${projectName}`)}`);
65
69
  console.log(` ${chalk.cyan(`npm start`)}\n`);
@@ -71,18 +75,15 @@ function consoleTips(projectName) {
71
75
  */
72
76
  async function _create(themeAppDescription, projectName) {
73
77
  const projectPath = path.resolve(WORKSPACE_PATH, projectName);
74
- const projectExists = await fsExtra.pathExists(projectPath);
75
78
 
76
- if (projectExists) {
79
+ if (fsExtra.pathExistsSync(projectPath)) {
77
80
  throw new Error(`Project directory "${projectName}" already exists.`);
78
81
  }
79
82
  await fsExtra.ensureDir(projectPath);
80
- const templatePath =
81
- THEME_APP_TYPE.BASIC_APP.description === themeAppDescription
82
- ? THEME_APP_TYPE.BASIC_APP.templatePath
83
- : THEME_APP_TYPE.EMBEDS_APP.templatePath;
83
+ const isBasicApp = themeAppDescription === THEME_APP_TYPE.BASIC_APP.description;
84
+ const templatePath = isBasicApp ? THEME_APP_TYPE.BASIC_APP.templatePath : THEME_APP_TYPE.EMBEDS_APP.templatePath;
84
85
  await fsExtra.copy(templatePath, projectPath);
85
- await initProj(projectPath, projectName);
86
+ await initProj(projectPath, projectName, isBasicApp);
86
87
  consoleTips(projectName);
87
88
  }
88
89
 
@@ -1,43 +1,51 @@
1
1
  const inquirer = require('inquirer');
2
2
  const chalk = require('chalk');
3
3
  const ora = require('ora');
4
- const { getThemeAppConfig } = require('../utils');
5
- const { getThemeAppVersionList, toDeployThemeApp } = require('../api/api');
4
+ const { getThemeExtensionConfig } = require('../utils');
5
+ const { getThemeAppVersionList, toDeployThemeApp } = require('../api');
6
6
 
7
- // 调用后端 API 进行部署
8
- async function deployVersion(appId, version) {
9
- // await new Promise((resolve) => setTimeout(resolve, 2000));
7
+ async function deployVersion(extensionId, versionInfo) {
10
8
  await toDeployThemeApp({
11
- extension_id: appId,
12
- version,
9
+ extension_id: extensionId,
10
+ version_id: versionInfo.version_id,
13
11
  type: 'enable'
14
12
  });
15
- console.log(chalk.green(`Version ${version} has been deployed successfully.`));
13
+ console.log(chalk.green(`Version ${versionInfo.version} has been deployed successfully.`));
16
14
  }
17
15
 
18
16
  async function usePrompt(versionList) {
19
17
  const choices = versionList.map((v) => ({
20
- name: `${v.version} (${v.date}) - ${v.description}`,
21
- value: v.version
18
+ name: `${v.version} (${v.exts}) - ${v.created_at}`,
19
+ value: v.version_id
22
20
  }));
23
21
  return inquirer.prompt([
24
22
  {
25
23
  type: 'list',
26
24
  name: 'selectedVersion',
27
25
  message: 'Select a version to deploy:',
28
- choices
26
+ choices,
27
+ loop: false
29
28
  }
30
29
  ]);
31
30
  }
32
31
 
33
32
  async function deploy() {
34
33
  try {
35
- const { appId } = await getThemeAppConfig();
34
+ const { extensionId } = await getThemeExtensionConfig();
35
+ if (!extensionId) {
36
+ throw new Error('ExtensionId is empty, please use `serve` command first.');
37
+ }
36
38
  const spinner = ora('Fetching version list...').start();
37
- const versionList = await getThemeAppVersionList();
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.');
44
+ }
38
45
  spinner.succeed('Version list loaded.');
39
46
  const { selectedVersion } = await usePrompt(versionList);
40
- await deployVersion(appId, selectedVersion);
47
+ const versionInfo = versionList.find((v) => v.version_id === selectedVersion);
48
+ await deployVersion(extensionId, versionInfo);
41
49
  } catch (error) {
42
50
  console.error(chalk.red(`[ERROR IN DEPLOY] ${error.message}`));
43
51
  }
@@ -1,25 +1,29 @@
1
1
  const chalk = require('chalk');
2
2
  const ora = require('ora');
3
- const { getThemeAppConfig, renderTable } = require('../utils');
4
- const { getThemeAppList } = require('../api/api');
3
+ const { renderTable } = require('../utils');
4
+ const { getThemeAppList } = require('../api');
5
5
 
6
6
  /**
7
7
  * 控制台提示
8
8
  */
9
9
  function consoleTips(versionList) {
10
- console.log(chalk.green('\n📜 Available Theme Apps:'));
11
- console.log(
12
- renderTable(versionList, [
13
- { label: 'Name', filed: 'name' },
14
- { label: 'Version', filed: 'version', color: 'yellowBright' },
15
- { label: 'Description', filed: 'description' }
16
- ])
17
- );
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
+ }
18
21
  }
19
22
 
20
23
  async function list() {
21
24
  try {
22
- const themeAppList = await getThemeAppList();
25
+ const res = await getThemeAppList();
26
+ const themeAppList = res.data?.data || [];
23
27
  consoleTips(themeAppList);
24
28
  } catch (error) {
25
29
  console.error(chalk.red(`[ERROR IN LIST] ${error.message}`));
@@ -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
+ };