shoplazza-cli 0.0.9 → 0.1.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 (61) hide show
  1. package/README.md +2 -6
  2. package/bin/shoplazza +6 -0
  3. package/examples/checkout-extension/README.md +19 -0
  4. package/examples/checkout-extension/extension.config.js +4 -0
  5. package/examples/checkout-extension/extensions/add-shipping-desc/extension.json +10 -0
  6. package/examples/checkout-extension/extensions/add-shipping-desc/src/index.js +7 -0
  7. package/examples/checkout-extension/extensions/ext-1/extension.json +10 -0
  8. package/examples/checkout-extension/extensions/ext-1/src/content.html +3 -0
  9. package/examples/checkout-extension/extensions/ext-1/src/index.html +5 -0
  10. package/examples/checkout-extension/extensions/ext-1/src/index.js +11 -0
  11. package/examples/checkout-extension/extensions/ext-1/src/script.html +3 -0
  12. package/examples/checkout-extension/extensions/ext-1/src/style.html +3 -0
  13. package/examples/checkout-extension/extensions/rewrite-navigate/extension.json +10 -0
  14. package/examples/checkout-extension/extensions/rewrite-navigate/src/content.html +38 -0
  15. package/examples/checkout-extension/extensions/rewrite-navigate/src/index.html +5 -0
  16. package/examples/checkout-extension/extensions/rewrite-navigate/src/index.js +12 -0
  17. package/examples/checkout-extension/extensions/rewrite-navigate/src/script.html +26 -0
  18. package/examples/checkout-extension/extensions/rewrite-navigate/src/style.html +23 -0
  19. package/examples/checkout-extension/package.json +17 -0
  20. package/lib/app/commands/deploy.js +0 -1
  21. package/lib/app/constants.js +22 -5
  22. package/lib/app/login.js +0 -1
  23. package/lib/auth/index.js +42 -0
  24. package/lib/checkout/api.js +156 -0
  25. package/lib/checkout/build/plugin/vite-plugin-add-extension-id.js +25 -0
  26. package/lib/checkout/build/plugin/vite-plugin-transform-extension-html.js +207 -0
  27. package/lib/checkout/build/vite.config.js +34 -0
  28. package/lib/checkout/build.js +39 -0
  29. package/lib/checkout/config.js +97 -0
  30. package/lib/checkout/console.js +32 -0
  31. package/lib/checkout/create.js +132 -0
  32. package/lib/checkout/delete.js +26 -0
  33. package/lib/checkout/deploy.js +59 -0
  34. package/lib/checkout/dev/client.js +73 -0
  35. package/lib/checkout/dev/index.js +142 -0
  36. package/lib/checkout/fields.js +29 -0
  37. package/lib/checkout/index.js +63 -0
  38. package/lib/checkout/preview.js +52 -0
  39. package/lib/checkout/pull.js +10 -0
  40. package/lib/checkout/push.js +140 -0
  41. package/lib/checkout/template/README.md +34 -0
  42. package/lib/checkout/template/_gitignore +4 -0
  43. package/lib/checkout/template/extension.config.js +4 -0
  44. package/lib/checkout/template/extensions/extension-template/extension.json +10 -0
  45. package/lib/checkout/template/extensions/extension-template/src/content.html +3 -0
  46. package/lib/checkout/template/extensions/extension-template/src/index.html +5 -0
  47. package/lib/checkout/template/extensions/extension-template/src/index.js +11 -0
  48. package/lib/checkout/template/extensions/extension-template/src/script.html +3 -0
  49. package/lib/checkout/template/extensions/extension-template/src/style.html +3 -0
  50. package/lib/checkout/template/package.json +17 -0
  51. package/lib/checkout/undeploy.js +40 -0
  52. package/lib/checkout/util.js +204 -0
  53. package/lib/checkout/verify.js +16 -0
  54. package/lib/checkout/version.js +7 -0
  55. package/lib/commands/login.js +3 -2
  56. package/lib/commands/theme/init.js +2 -2
  57. package/lib/commands/theme/pull.js +1 -1
  58. package/lib/config.js +4 -0
  59. package/lib/db/user.js +5 -2
  60. package/lib/utils.js +57 -5
  61. package/package.json +29 -3
@@ -0,0 +1,204 @@
1
+ const AdmZip = require('adm-zip');
2
+ const { cwd, configFile } = require('./config');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { consoleError, consoleBlue } = require('./console');
6
+ const inquirer = require('inquirer');
7
+
8
+ const walkSync = (currentDirPath, callback) => {
9
+ fs.readdirSync(currentDirPath, { withFileTypes: true }).forEach(function (dirent) {
10
+ var filePath = path.join(currentDirPath, dirent.name);
11
+ if (dirent.isFile()) {
12
+ callback(filePath, dirent);
13
+ } else if (dirent.isDirectory()) {
14
+ walkSync(filePath, callback);
15
+ }
16
+ });
17
+ };
18
+
19
+ function getExtensionPathById(extensionId) {
20
+ return path.join(cwd, !cwd.includes('/extensions') ? 'extensions' : '', extensionId);
21
+ }
22
+
23
+ /**
24
+ * 根据id获取当前extension信息
25
+ * @param {*} extensionId
26
+ * @returns
27
+ */
28
+ function getExtensionInfo(extensionId) {
29
+ let result = {};
30
+ const currentPath = path.resolve(cwd);
31
+ const isInExtensionDir = !!fs.readdirSync(currentPath).find((f) => f === configFile);
32
+ // 已经在一个extension内部
33
+ if (isInExtensionDir) {
34
+ const extensionId = currentPath.split('/').pop();
35
+ result = {
36
+ path: currentPath,
37
+ id: extensionId
38
+ };
39
+ } else if (extensionId) {
40
+ const extensionPath = path.join(cwd, !cwd.includes('/extensions') ? 'extensions' : '', extensionId);
41
+ if (!fs.existsSync(extensionPath)) {
42
+ consoleError(`The extension '${extensionId}' does not exist.`);
43
+ throw `The extension '${extensionId}' does not exist.`;
44
+ }
45
+
46
+ result = {
47
+ id: extensionId,
48
+ path: extensionPath
49
+ };
50
+ } else {
51
+ let dirPath = path.resolve(cwd);
52
+
53
+ if (!dirPath.includes('extensions')) {
54
+ consoleError('Please specify Extension id through --id.');
55
+ throw 'not_id';
56
+ }
57
+ const extensionId = dirPath.split('/').pop();
58
+ result = {
59
+ id: extensionId,
60
+ path: dirPath
61
+ };
62
+ }
63
+ result.distPath = getDistPath();
64
+ if (fs.existsSync(result.distPath)) {
65
+ result.distName = fs.readdirSync(result.distPath).find((f) => f.includes(result.id));
66
+ }
67
+ return result;
68
+ }
69
+
70
+ function getExtensionConfig(id) {
71
+ const info = getExtensionInfo(id);
72
+ const config = path.join(info.path, configFile);
73
+
74
+ if (!fs.existsSync(config)) {
75
+ consoleError(`Extension '${info.id}' not exist ${configFile}.`);
76
+ throw 'not_exist_config_file';
77
+ }
78
+ return JSON.parse(fs.readFileSync(config, 'utf-8'));
79
+ }
80
+
81
+ function getRootPath() {
82
+ return cwd;
83
+ }
84
+
85
+ function getExtensionsPath() {
86
+ return path.join(getRootPath(), 'extensions');
87
+ }
88
+
89
+ function getDistPath() {
90
+ return path.join(getRootPath(), 'dist');
91
+ }
92
+
93
+ function getProjectConfig() {
94
+ return require(path.join(getRootPath(), 'extension.config.js'));
95
+ }
96
+
97
+ function copy(src, dest) {
98
+ const stat = fs.statSync(src);
99
+ if (stat.isDirectory()) {
100
+ copyDir(src, dest);
101
+ } else {
102
+ fs.copyFileSync(src, dest);
103
+ }
104
+ }
105
+
106
+ function copyDir(srcDir, destDir) {
107
+ fs.mkdirSync(destDir, { recursive: true });
108
+ for (const file of fs.readdirSync(srcDir)) {
109
+ const srcFile = path.resolve(srcDir, file);
110
+ const destFile = path.resolve(destDir, file);
111
+ copy(srcFile, destFile);
112
+ }
113
+ }
114
+
115
+ /**
116
+ * 选择模式,返回所选extension信息
117
+ * @param {Array} extensionList extension列表
118
+ * @param {String} type 类型:push | deploy | undeploy | preview
119
+ * @returns {Object} 所选extension信息
120
+ */
121
+ async function useSelectExtensionMode(extensionList = [], type = 'push') {
122
+ const choices = extensionList.map((item, index) => ({
123
+ name: (type === 'push' && index === 0) ? item.name : `${item.name}(${item.extension_id})`,
124
+ value: item.extension_id
125
+ }))
126
+ if (!choices.length) {
127
+ consoleBlue(`No extensions available to ${type}.`);
128
+ process.exit(1);
129
+ }
130
+ const { extensionId } = await inquirer
131
+ .prompt([
132
+ {
133
+ type: 'list',
134
+ name: 'extensionId',
135
+ message: `Please select an extension to ${type}:`,
136
+ prefix: '*',
137
+ loop: false,
138
+ choices,
139
+ },
140
+ ])
141
+ return extensionList.find((item) => item.extension_id === extensionId);
142
+ }
143
+
144
+ /**
145
+ * 重写指定extension的extension.json文件内容
146
+ * @param {String} extensionName extension名称
147
+ * @param {*} extensionConfig extension配置
148
+ */
149
+ function setExtensionConfig(extensionName, extensionConfig) {
150
+ const info = getExtensionInfo(extensionName);
151
+ const configFilePath = path.join(info.path, configFile);
152
+ if (!fs.existsSync(configFilePath)) {
153
+ consoleError(`Extension '${extensionName}' does not exist in ${configFile}.`);
154
+ throw 'Config file does not exist';
155
+ } else {
156
+ fs.writeFile(configFilePath, JSON.stringify(extensionConfig, null, 2), (err) => {
157
+ if (err) {
158
+ consoleError(`Error writing file to disk: ${err}`);
159
+ }
160
+ });
161
+ }
162
+ }
163
+
164
+ /**
165
+ * 判断是否为本地extension
166
+ * @param {String} extensionInfo extension信息
167
+ */
168
+ function checkLocalExtension(extensionInfo) {
169
+ const extensionPath = path.resolve(cwd, './extensions', extensionInfo.name || extensionInfo.extension_id); // todo: 此处extension_id兼容已存在extension,可考虑去掉
170
+ if (fs.existsSync(extensionPath)) {
171
+ const extensionJsonPath = path.resolve(extensionPath, './extension.json');
172
+ const localExtensionInfo = JSON.parse(fs.readFileSync(extensionJsonPath, 'utf8'));
173
+ if (localExtensionInfo.extensionId !== extensionInfo.extension_id) {
174
+ consoleError(`The extension ${extensionInfo.name}(${extensionInfo.extension_id}) does not exist in your local project.`);
175
+ throw `The extension ${extensionInfo.name}(${extensionInfo.extension_id}) does not exist in your local project.`;
176
+ }
177
+ } else {
178
+ consoleError(`The extension ${extensionInfo.name}(${extensionInfo.extension_id}) does not exist in your local project.`);
179
+ throw `The extension ${extensionInfo.name}(${extensionInfo.extension_id}) does not exist in your local project.`;
180
+ }
181
+ }
182
+
183
+ module.exports = {
184
+ copy,
185
+ getRootPath,
186
+ getDistPath,
187
+ getExtensionsPath,
188
+ getProjectConfig,
189
+ getExtensionInfo,
190
+ getExtensionConfig,
191
+ getExtensionPathById,
192
+ getFileJson: async (path) => JSON.parse(await fs.readFileSync(path)),
193
+ debug: async (...log) => {
194
+ ~process.argv.indexOf('--debug') && console.log(`${log.join(' ')}`);
195
+ },
196
+ zip: (filePath, uuid) => {
197
+ const zip = new AdmZip();
198
+ zip.addLocalFolder(filePath, uuid);
199
+ zip.writeZip(`${cwd}/${uuid}.zip`);
200
+ },
201
+ useSelectExtensionMode,
202
+ setExtensionConfig,
203
+ checkLocalExtension
204
+ };
@@ -0,0 +1,16 @@
1
+ const api = require('./api');
2
+ const { consoleError } = require('./console');
3
+ const { getProjectConfig } = require('./util');
4
+
5
+ async function verifyConfig(commands) {
6
+ const configJson = getProjectConfig();
7
+ if (!configJson.token || !configJson.store) {
8
+ consoleError(`Must provide the token and store of the shop in extension.config.js config file.`);
9
+ throw 'not_exist_token_or_store';
10
+ }
11
+ return configJson;
12
+ }
13
+
14
+ module.exports = {
15
+ verifyConfig
16
+ };
@@ -0,0 +1,7 @@
1
+ const semver = require("semver");
2
+ const { engines } = require("../../package");
3
+ const version = engines.node;
4
+ if (!semver.satisfies(process.version, version)) {
5
+ console.error(`Required node version ${version}`);
6
+ process.exit(1);
7
+ }
@@ -7,7 +7,7 @@ const { hasBeenSetAnalytics, setAnalyticsConfig } = require('../db/analytics');
7
7
  const log = require('../log');
8
8
  const { getShopDetail } = require('../openAPI/api');
9
9
  const getCode = require('../auth/getCode');
10
- const { postAccessToken, getUserInfo, postExchangeToken } = require('../auth');
10
+ const { postAccessToken, getUserInfo, postExchangeToken, postStoreToken } = require('../auth');
11
11
  const { loginIntoPartner } = require('../app/login');
12
12
 
13
13
  let spinner;
@@ -39,6 +39,7 @@ const checkAndLogin = async (store) => {
39
39
  await postAccessToken(code, store);
40
40
  await getUserInfo(store);
41
41
  await postExchangeToken(store);
42
+ await postStoreToken(store);
42
43
  spinner?.stop?.();
43
44
  log.info(`${chalk.green('✓')} Finalizing authentication`);
44
45
  log.info(`Logged into ${chalk.green(get('store_domain'))}`);
@@ -80,7 +81,7 @@ const loginIntoStore = async (store) => {
80
81
  }
81
82
  ]);
82
83
  if (answers.store) {
83
- if (!answers.store.includes('myshoplaza.com') || !answers.store.includes('myshoplaza.com')) {
84
+ if (!answers.store.includes('myshoplaza.com')) {
84
85
  log.error(
85
86
  chalk.red(
86
87
  `✗ Invalid store provided ${answers.store}. Please provide the store in the following format: developer.myshoplaza.com`
@@ -15,8 +15,8 @@ const createDirAndCloneTheme = async (directory) => {
15
15
  return;
16
16
  }
17
17
  fs.mkdirSync(themeDir);
18
- const spinner = ora(chalk.cyan(`Cloning https://github.com/Shoplazza/LifeStyle into ${directory}…`)).start();
19
- await execa('git', ['clone', 'https://github.com/Shoplazza/LifeStyle', directory]);
18
+ const spinner = ora(chalk.cyan(`Cloning https://github.com/Shoplazza/Nova-2023 into ${directory}…`)).start();
19
+ await execa('git', ['clone', 'https://github.com/Shoplazza/Nova-2023', directory]);
20
20
  fs.rmSync(path.join(process.cwd(), `${directory}/.git`), { recursive: true });
21
21
  spinner.stop();
22
22
  log.info(chalk.green(`✓ Cloned into ${directory}`));
@@ -56,7 +56,7 @@ module.exports = async (options) => {
56
56
  await pullThemeFiles(answers.theme);
57
57
  }
58
58
  } catch (error) {
59
- log.error(chalk.red(`✗ Failed to pull theme`));
59
+ log.error(chalk.red(`✗ Failed to pull theme: ${error?.response?.status}`));
60
60
  Sentry.captureException(error);
61
61
  }
62
62
  };
package/lib/config.js CHANGED
@@ -6,3 +6,7 @@ exports.THEME_DIRS = ['assets', 'config', 'layout', 'locales', 'sections', 'snip
6
6
  exports.DEV_SSO_AUTH_URL = 'https://sso.dev.shoplazza.com';
7
7
  exports.DEV_ACCOUNT_URL = 'https://myaccount.dev.shoplazza.com';
8
8
  exports.DEV_CLIENT_ID = 'b630b285-e098-4c51-a7a4-d0240c9fc209';
9
+
10
+ exports.STG_SSO_AUTH_URL = 'https://sso.stg.shoplazza.com';
11
+ exports.STG_ACCOUNT_URL = 'https://myaccount.stg.shoplazza.com';
12
+ exports.STG_CLIENT_ID = 'b630b285-e098-4c51-a7a4-d0240c9fc209';
package/lib/db/user.js CHANGED
@@ -9,6 +9,7 @@ const createTableIfNeeded = () => {
9
9
  theme_id text,
10
10
  theme_name text,
11
11
  store_domain text,
12
+ store_session text,
12
13
  user_id text
13
14
  )`);
14
15
  createTable.run();
@@ -27,10 +28,11 @@ const insertOrReplace = ({
27
28
  theme_id = get('theme_id'),
28
29
  theme_name = get('theme_name'),
29
30
  store_domain = get('store_domain'),
31
+ store_session = get('store_session'),
30
32
  user_id = get('user_id')
31
33
  }) => {
32
34
  const stmt = db.prepare(
33
- `insert or replace into user (id, access_token, session_id, exchange_token, theme_id, theme_name, store_domain, user_id) values (
35
+ `insert or replace into user (id, access_token, session_id, exchange_token, theme_id, theme_name, store_domain, store_session, user_id) values (
34
36
  (select id from user where access_token = @access_token),
35
37
  @access_token,
36
38
  @session_id,
@@ -38,10 +40,11 @@ const insertOrReplace = ({
38
40
  @theme_id,
39
41
  @theme_name,
40
42
  @store_domain,
43
+ @store_session,
41
44
  @user_id
42
45
  )`
43
46
  );
44
- stmt.run({ access_token, session_id, exchange_token, theme_id, theme_name, store_domain, user_id });
47
+ stmt.run({ access_token, session_id, exchange_token, theme_id, theme_name, store_domain, store_session, user_id });
45
48
  };
46
49
 
47
50
  const emptyUserData = () => {
package/lib/utils.js CHANGED
@@ -3,7 +3,19 @@ const fs = require('fs-extra');
3
3
  const AdmZip = require('adm-zip');
4
4
  const chalk = require('chalk');
5
5
 
6
- const { SSO_AUTH_URL, ACCOUNT_URL, CLIENT_ID, DEV_SSO_AUTH_URL, DEV_ACCOUNT_URL, DEV_CLIENT_ID } = require('./config');
6
+ const {
7
+ SSO_AUTH_URL,
8
+ ACCOUNT_URL,
9
+ CLIENT_ID,
10
+ DEV_SSO_AUTH_URL,
11
+ DEV_ACCOUNT_URL,
12
+ DEV_CLIENT_ID,
13
+ STG_CLIENT_ID,
14
+ STG_ACCOUNT_URL,
15
+ STG_SSO_AUTH_URL
16
+ } = require('./config');
17
+
18
+ const ZIP_IGNORE_FOLDER = ['.git', '.DS_Store'];
7
19
 
8
20
  exports.unzipTheme = (zipPath, outputPath) => {
9
21
  const zip = new AdmZip(zipPath);
@@ -22,7 +34,26 @@ exports.unzipTheme = (zipPath, outputPath) => {
22
34
 
23
35
  exports.zipTheme = (filePath, themeName) => {
24
36
  const zip = new AdmZip();
25
- zip.addLocalFolder(filePath, themeName);
37
+
38
+ // Old code
39
+ // zip.addLocalFolder(filePath, themeName);
40
+
41
+ // zip, but ignore some folder
42
+ const lsDir = fs.readdirSync(filePath);
43
+ lsDir.forEach((lsItem) => {
44
+ const lsItemStat = fs.statSync(path.join(filePath, lsItem));
45
+
46
+ if (ZIP_IGNORE_FOLDER.includes(lsItem)) {
47
+ return;
48
+ }
49
+
50
+ if (lsItemStat.isDirectory()) {
51
+ zip.addLocalFolder(path.join(filePath, lsItem), path.join(themeName, lsItem));
52
+ } else if (lsItemStat.isFile()) {
53
+ zip.addLocalFile(path.join(filePath, lsItem), path.join(themeName, lsItem));
54
+ }
55
+ });
56
+
26
57
  zip.writeZip(`${process.cwd()}/${themeName}.zip`);
27
58
  };
28
59
 
@@ -48,14 +79,35 @@ exports.formatThemeList = (themes, defaultThemeId) => {
48
79
 
49
80
  exports.sleep = (time) => new Promise((resolve) => setTimeout(resolve, time));
50
81
 
82
+ function getEnv(store) {
83
+ return store.includes('dev.myshoplaza.com') ? 'dev' : store.includes('stg.myshoplaza.com') ? 'stg' : 'prod';
84
+ }
85
+
86
+ const CLIENT_ID_ENV_MAP = {
87
+ dev: DEV_CLIENT_ID,
88
+ stg: STG_CLIENT_ID,
89
+ prod: CLIENT_ID
90
+ };
91
+
51
92
  exports.getClientId = (store) => {
52
- return store.includes('dev.') ? DEV_CLIENT_ID : CLIENT_ID;
93
+ return CLIENT_ID_ENV_MAP[getEnv(store)];
53
94
  };
54
95
 
96
+ const ACCOUNT_URL_ENV_MAP = {
97
+ dev: DEV_ACCOUNT_URL,
98
+ stg: STG_ACCOUNT_URL,
99
+ prod: ACCOUNT_URL
100
+ };
55
101
  exports.getAccountUrl = (store) => {
56
- return store.includes('dev.myshoplaza.com') ? DEV_ACCOUNT_URL : ACCOUNT_URL;
102
+ return ACCOUNT_URL_ENV_MAP[getEnv(store)];
103
+ };
104
+
105
+ const SSO_AUTH_URL_MAP = {
106
+ dev: DEV_SSO_AUTH_URL,
107
+ stg: STG_SSO_AUTH_URL,
108
+ prod: SSO_AUTH_URL
57
109
  };
58
110
 
59
111
  exports.getSSOAuthUrl = (store) => {
60
- return store.includes('dev.myshoplaza.com') ? DEV_SSO_AUTH_URL : SSO_AUTH_URL;
112
+ return SSO_AUTH_URL_MAP[getEnv(store)];
61
113
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shoplazza-cli",
3
- "version": "0.0.9",
3
+ "version": "0.1.8",
4
4
  "description": "",
5
5
  "main": "bin/shoplazza",
6
6
  "engines": {
@@ -28,26 +28,52 @@
28
28
  "dependencies": {
29
29
  "@sentry/node": "^6.19.7",
30
30
  "@sentry/tracing": "^6.19.7",
31
+ "@shoplazza/extension-ui": "^1.0.0",
31
32
  "adm-zip": "^0.5.9",
33
+ "ali-oss": "^6.17.1",
32
34
  "archiver": "^5.3.1",
33
- "axios": "^0.27.1",
34
- "better-sqlite3": "^7.5.1",
35
+ "axios": "^1.6.8",
36
+ "better-sqlite3": "^11.5.0",
35
37
  "chalk": "^4.1.2",
38
+ "chokidar": "^3.6.0",
39
+ "classnames": "~2.3.2",
36
40
  "clean-css": "^5.3.1",
41
+ "colors": "^1.4.0",
37
42
  "commander": "^9.2.0",
43
+ "connect": "^3.7.0",
38
44
  "download-git-repo": "^3.0.2",
39
45
  "execa": "^5.1.1",
46
+ "extension-ui": "^1.0.6",
47
+ "fancy-log": "~1.3.3",
48
+ "file-type": "~16.5.0",
40
49
  "form-data": "^4.0.0",
41
50
  "fs-extra": "^10.1.0",
42
51
  "glob": "^8.0.3",
52
+ "imagemin": "~8.0.0",
53
+ "imagemin-jpegtran": "~7.0.0",
54
+ "imagemin-pngquant": "~9.0.2",
55
+ "imagemin-svgo": "~9.0.0",
43
56
  "inquirer": "^8.2.3",
57
+ "js-queue": "~2.0.2",
58
+ "jscodeshift": "^0.15.0",
44
59
  "livereload": "^0.9.3",
60
+ "loading-cli": "^1.1.2",
61
+ "md5": "~2.3.0",
62
+ "mime": "^3.0.0",
63
+ "mobx": "~6.9.0",
64
+ "node-fetch": "^2.6.7",
45
65
  "node-watch": "^0.7.3",
46
66
  "open": "^8.4.0",
47
67
  "ora": "^5.4.1",
68
+ "process": "~0.11.10",
69
+ "semver": "~7.3.5",
70
+ "serve-static": "^1.15.0",
48
71
  "spark-md5": "^3.0.2",
49
72
  "uglify-js": "^3.17.4",
50
73
  "update-notifier": "^5.1.0",
74
+ "vite": "~4.3.1",
75
+ "vite-plugin-inspect": "^0.7.25",
76
+ "ws": "^8.17.0",
51
77
  "yargs": "^17.5.0"
52
78
  }
53
79
  }