shoplazza-cli 1.0.7 → 1.0.9
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/README.md +83 -2
- package/bin/shoplazza +8 -15
- package/lib/app/api/index.js +96 -0
- package/lib/app/commands/build.js +101 -53
- package/lib/app/commands/connect.js +73 -0
- package/lib/app/commands/create.js +105 -0
- package/lib/app/commands/deploy.js +45 -208
- package/lib/app/commands/list.js +35 -0
- package/lib/app/commands/release.js +59 -0
- package/lib/app/commands/serve.js +179 -0
- package/lib/app/commands/versions.js +55 -0
- package/lib/app/index.js +22 -30
- package/lib/app/template/basic-app/README.md +125 -0
- package/lib/app/template/basic-app/extension.config.json +4 -0
- package/lib/app/template/basic-app/package.json +18 -0
- package/lib/app/template/basic-app/theme-app/assets/index.css +4 -0
- package/lib/app/template/basic-app/theme-app/assets-manifest.json +1 -0
- package/lib/app/template/basic-app/theme-app/blocks/index.liquid +16 -0
- package/lib/app/template/basic-app/theme-app/locales/ar-SA.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/de-DE.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/en-US.json +6 -0
- package/lib/app/template/basic-app/theme-app/locales/es-ES.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/fr-FR.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/id-ID.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/it-IT.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/ja-JP.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/ko-KR.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/nl-NL.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/pl-PL.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/pt-PT.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/ru-RU.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/th-TH.json +1 -0
- package/lib/app/template/basic-app/theme-app/locales/zh-CN.json +6 -0
- package/lib/app/template/basic-app/theme-app/locales/zh-TW.json +1 -0
- package/lib/app/template/basic-app/theme-app/snippets/index.liquid +8 -0
- package/lib/app/template/embed-app/README.md +125 -0
- package/lib/app/template/embed-app/extension.config.json +4 -0
- package/lib/app/template/embed-app/package.json +18 -0
- package/lib/app/template/embed-app/theme-app/assets-manifest.json +1 -0
- package/lib/app/template/embed-app/theme-app/blocks/index.liquid +18 -0
- package/lib/app/template/embed-app/theme-app/locales/ar-SA.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/de-DE.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/en-US.json +6 -0
- package/lib/app/template/embed-app/theme-app/locales/es-ES.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/fr-FR.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/id-ID.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/it-IT.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/ja-JP.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/ko-KR.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/nl-NL.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/pl-PL.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/pt-PT.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/ru-RU.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/th-TH.json +1 -0
- package/lib/app/template/embed-app/theme-app/locales/zh-CN.json +6 -0
- package/lib/app/template/embed-app/theme-app/locales/zh-TW.json +1 -0
- package/lib/app/template/embed-app/theme-app/snippets/index.liquid +8 -0
- package/lib/app/template/embed-app/theme-app/snippets/index_css.liquid +6 -0
- package/lib/app/utils/config.js +32 -0
- package/lib/app/utils/index.js +213 -0
- package/lib/auth/getCode.js +2 -2
- package/lib/auth/index.js +2 -2
- package/lib/check.js +28 -0
- package/lib/checkout/api.js +12 -36
- package/lib/checkout/build.js +1 -1
- package/lib/checkout/create.js +1 -1
- package/lib/checkout/deploy.js +1 -1
- package/lib/checkout/dev/index.js +1 -1
- package/lib/checkout/fields.js +1 -1
- package/lib/checkout/preview.js +1 -1
- package/lib/checkout/pull.js +1 -0
- package/lib/checkout/push.js +1 -1
- package/lib/checkout/undeploy.js +1 -1
- package/lib/checkout/util.js +1 -1
- package/lib/checkout/verify.js +1 -1
- package/lib/commands/login.js +1 -1
- package/lib/commands/logout.js +1 -1
- package/lib/commands/theme/delete.js +1 -1
- package/lib/commands/theme/package.js +1 -1
- package/lib/commands/theme/publish.js +1 -1
- package/lib/commands/theme/pull.js +1 -1
- package/lib/commands/theme/push.js +1 -1
- package/lib/commands/theme/serve.js +2 -2
- package/lib/{app → common}/login.js +1 -1
- package/lib/function/bin/index.js +20 -0
- package/lib/function/bin/javy/javy-arm-linux-v5.0.1 +0 -0
- package/lib/function/bin/javy/javy-arm-macos-v5.0.1 +0 -0
- package/lib/function/bin/javy/javy-x86_64-linux-v5.0.1 +0 -0
- package/lib/function/bin/javy/javy-x86_64-macos-v5.0.1 +0 -0
- package/lib/function/bin/javy/javy-x86_64-windows-v5.0.1 +0 -0
- package/lib/function/commands/compile.js +42 -0
- package/lib/function/commands/create.js +77 -0
- package/lib/function/commands/list.js +18 -0
- package/lib/function/commands/release.js +69 -0
- package/lib/function/index.js +24 -0
- package/lib/function/template/js/README.md +37 -0
- package/lib/function/template/js/_gitignore +4 -0
- package/lib/function/template/js/extension.config.json +5 -0
- package/lib/function/template/js/package.json +17 -0
- package/lib/function/template/js/src/index.js +64 -0
- package/lib/function/utils.js +29 -0
- package/lib/openAPI/api.js +1 -1
- package/lib/openAPI/index.js +21 -11
- package/lib/oss.js +99 -0
- package/lib/partner-api/axios.js +67 -0
- package/lib/partner-api/index.js +79 -0
- package/lib/{checkout → utils}/console.js +3 -2
- package/lib/utils/env.js +17 -0
- package/lib/utils/file.js +48 -0
- package/lib/utils/platform.js +37 -0
- package/lib/{utils.js → utils/utils.js} +52 -0
- package/package.json +2 -2
- package/lib/app/commands/generate.js +0 -50
- package/lib/app/commands/publish.js +0 -52
- package/lib/app/extensions/index.js +0 -13
- package/lib/app/extensions/theme-app.js +0 -103
- package/lib/app/inquirers/version.js +0 -131
- /package/lib/{app → common}/constants.js +0 -0
- /package/lib/{app → common}/db/partner.js +0 -0
- /package/lib/{app → common}/inquirers/choose-app.js +0 -0
- /package/lib/{app → common}/inquirers/choose-partner.js +0 -0
- /package/lib/{app → common}/log.js +0 -0
- /package/lib/{app → common}/logout.js +0 -0
- /package/lib/{config.js → utils/config.js} +0 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const { consoleError, consoleSuccess } = require('../../utils/console');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const inquirer = require('inquirer');
|
|
5
|
+
const { copy } = require('../../utils/file');
|
|
6
|
+
|
|
7
|
+
const cwd = process.cwd();
|
|
8
|
+
|
|
9
|
+
const templateDir = path.resolve(__dirname, '../template');
|
|
10
|
+
|
|
11
|
+
const renameFiles = {
|
|
12
|
+
_gitignore: '.gitignore'
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 使用cli创建一个项目
|
|
17
|
+
* @param {} command 项目名
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
async function createFuncExtension(command) {
|
|
21
|
+
const { language, extensionName } = await inquirer.prompt([
|
|
22
|
+
{
|
|
23
|
+
type: 'input',
|
|
24
|
+
name: 'extensionName',
|
|
25
|
+
message: 'Enter the extension name:',
|
|
26
|
+
prefix: '*'
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
type: 'list',
|
|
30
|
+
name: 'language',
|
|
31
|
+
message: 'Select a language:',
|
|
32
|
+
choices: [
|
|
33
|
+
{
|
|
34
|
+
name: 'javascript',
|
|
35
|
+
value: 'js'
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
prefix: '*'
|
|
39
|
+
}
|
|
40
|
+
]);
|
|
41
|
+
const projectDir = extensionName.replace(/\/+$/g, '');
|
|
42
|
+
const fullTempDir = path.join(templateDir, language);
|
|
43
|
+
const root = path.join(cwd, projectDir);
|
|
44
|
+
if (fs.existsSync(root)) {
|
|
45
|
+
consoleError(`the directory '${projectDir}' is exist.`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
fs.mkdirSync(root, { recursive: true });
|
|
49
|
+
|
|
50
|
+
const write = (file, content) => {
|
|
51
|
+
const targetPath = path.join(root, renameFiles[file] ?? file);
|
|
52
|
+
if (content) {
|
|
53
|
+
fs.writeFileSync(targetPath, content);
|
|
54
|
+
} else {
|
|
55
|
+
copy(path.join(fullTempDir, file), targetPath);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const files = fs.readdirSync(fullTempDir);
|
|
60
|
+
for (const file of files.filter((f) => !['package.json'].includes(f))) {
|
|
61
|
+
write(file);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(fullTempDir, `package.json`), 'utf-8'));
|
|
65
|
+
pkg.name = projectDir;
|
|
66
|
+
write('package.json', JSON.stringify(pkg, null, 2) + '\n');
|
|
67
|
+
|
|
68
|
+
const config = JSON.parse(fs.readFileSync(path.join(fullTempDir, `extension.config.json`), 'utf-8'));
|
|
69
|
+
config.extensionName = extensionName;
|
|
70
|
+
write('extension.config.json', JSON.stringify(config, null, 2) + '\n');
|
|
71
|
+
|
|
72
|
+
consoleSuccess(`Successfully created extension project '${extensionName}'.`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = {
|
|
76
|
+
createFuncExtension
|
|
77
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const partnerAPI = require('../../partner-api');
|
|
2
|
+
const { requestAppSecretWhenNotExist } = require('../utils');
|
|
3
|
+
|
|
4
|
+
async function getFunctions() {
|
|
5
|
+
const data = await partnerAPI.getFunctionList();
|
|
6
|
+
return data.functions;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
async function listFunctionExtension() {
|
|
10
|
+
await requestAppSecretWhenNotExist();
|
|
11
|
+
const list = await getFunctions();
|
|
12
|
+
console.log(list.map(({ source_code, ...other }) => other));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = {
|
|
16
|
+
getFunctions,
|
|
17
|
+
listFunctionExtension
|
|
18
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const chalk = require('chalk');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const loadingCli = require('loading-cli');
|
|
6
|
+
const { requestAppSecretWhenNotExist } = require('../utils');
|
|
7
|
+
const { compileJsToWasm } = require('./compile');
|
|
8
|
+
const { getConfigJson, updateConfigJson } = require('../../utils/file');
|
|
9
|
+
const partnerAPI = require('../../partner-api');
|
|
10
|
+
const { consoleError } = require('../../utils/console');
|
|
11
|
+
const FormData = require('form-data');
|
|
12
|
+
|
|
13
|
+
async function createOrUpdateFuncExtension() {
|
|
14
|
+
const config = getConfigJson();
|
|
15
|
+
const functionId = config.extensionId;
|
|
16
|
+
const formData = new FormData();
|
|
17
|
+
formData.append('namespace', 'cart_transform');
|
|
18
|
+
formData.append('name', config.extensionName);
|
|
19
|
+
formData.append('source_code', fs.readFileSync(path.resolve(process.cwd(), 'src/index.js'), { encoding: 'utf-8' }));
|
|
20
|
+
formData.append('source_code', 'hello');
|
|
21
|
+
formData.append(
|
|
22
|
+
'file',
|
|
23
|
+
fs.createReadStream(path.resolve(process.cwd(), 'dist', `${config.extensionName}.wasm`), {
|
|
24
|
+
filename: `${config.extensionName}.wasm`,
|
|
25
|
+
contentType: 'application/wasm'
|
|
26
|
+
})
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
let data;
|
|
30
|
+
if (!functionId) {
|
|
31
|
+
const loading = loadingCli('create an new function extension');
|
|
32
|
+
loading.start();
|
|
33
|
+
data = await partnerAPI
|
|
34
|
+
.createFunctionExtension(formData)
|
|
35
|
+
.then((res) => {
|
|
36
|
+
loading.succeed();
|
|
37
|
+
return res;
|
|
38
|
+
})
|
|
39
|
+
.catch((err) => {
|
|
40
|
+
loading.fail();
|
|
41
|
+
consoleError(err, err.response.data);
|
|
42
|
+
});
|
|
43
|
+
} else {
|
|
44
|
+
const loading = loadingCli('update function extension');
|
|
45
|
+
loading.start();
|
|
46
|
+
formData.append('function_id', functionId);
|
|
47
|
+
data = await partnerAPI
|
|
48
|
+
.updateFunctionExtension(functionId, formData)
|
|
49
|
+
.then((res) => {
|
|
50
|
+
loading.succeed();
|
|
51
|
+
return res;
|
|
52
|
+
})
|
|
53
|
+
.catch((err) => {
|
|
54
|
+
loading.fail();
|
|
55
|
+
consoleError(err, err.response);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
data && updateConfigJson({ extensionId: data.function_id, version: data.version });
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function releaseFunctionExtension(command) {
|
|
62
|
+
await requestAppSecretWhenNotExist();
|
|
63
|
+
await compileJsToWasm();
|
|
64
|
+
await createOrUpdateFuncExtension();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = {
|
|
68
|
+
releaseFunctionExtension
|
|
69
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
function makeFunctionCommand(_program) {
|
|
2
|
+
const program = _program.command('function').description('Shoplazza function cli');
|
|
3
|
+
|
|
4
|
+
program
|
|
5
|
+
.command('create')
|
|
6
|
+
.description('create a extension project')
|
|
7
|
+
.action(require('./commands/create').createFuncExtension);
|
|
8
|
+
|
|
9
|
+
program
|
|
10
|
+
.command('list')
|
|
11
|
+
.description('list all function of current app')
|
|
12
|
+
.action(require('./commands/list').listFunctionExtension);
|
|
13
|
+
|
|
14
|
+
program.command('compile').description('compile js to wasm').action(require('./commands/compile').compileJsToWasm);
|
|
15
|
+
|
|
16
|
+
program
|
|
17
|
+
.command('release')
|
|
18
|
+
.description('release a version of function extension')
|
|
19
|
+
.action(require('./commands/release').releaseFunctionExtension);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
module.exports = {
|
|
23
|
+
makeFunctionCommand
|
|
24
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Checkout Extension
|
|
2
|
+
## Getting started
|
|
3
|
+
|
|
4
|
+
1. 安装依赖
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
npm i
|
|
8
|
+
```
|
|
9
|
+
2. 绑定app
|
|
10
|
+
```
|
|
11
|
+
npm run connect
|
|
12
|
+
```
|
|
13
|
+
3. release extension
|
|
14
|
+
```
|
|
15
|
+
npm run release
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hello",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"dependencies": {},
|
|
7
|
+
"devDependencies": {},
|
|
8
|
+
"scripts": {
|
|
9
|
+
"dev": "shoplazza function dev",
|
|
10
|
+
"connect": "shoplazza function connect",
|
|
11
|
+
"release": "shoplazza function release",
|
|
12
|
+
"list": "shoplazza function list"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "",
|
|
16
|
+
"license": "ISC"
|
|
17
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
const input = readInput();
|
|
2
|
+
const result = run(input);
|
|
3
|
+
writeOutput(result);
|
|
4
|
+
|
|
5
|
+
function run(input) {
|
|
6
|
+
const runResult = {
|
|
7
|
+
operations: {
|
|
8
|
+
update: []
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
input.cart.line_items.forEach((lineItem) => {
|
|
13
|
+
lineItem.product.metafields.forEach((metafield) => {
|
|
14
|
+
// key是自己定义的metafield名。如果有同名的key,可用namespace用于区分
|
|
15
|
+
if (metafield.namespace === 'custom-option' && metafield.key === 'adjust-10-price') {
|
|
16
|
+
runResult.operations.update.push({
|
|
17
|
+
id: lineItem.id,
|
|
18
|
+
price: {
|
|
19
|
+
adjustment_fixed_price: '10' // 设置定制的价格10元
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
return runResult;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function readInput() {
|
|
29
|
+
const chunkSize = 1024;
|
|
30
|
+
const inputChunks = [];
|
|
31
|
+
let totalBytes = 0;
|
|
32
|
+
// Read all the available bytes
|
|
33
|
+
while (1) {
|
|
34
|
+
const buffer = new Uint8Array(chunkSize);
|
|
35
|
+
// Stdin file descriptor
|
|
36
|
+
const fd = 0;
|
|
37
|
+
const bytesRead = Javy.IO.readSync(fd, buffer);
|
|
38
|
+
totalBytes += bytesRead;
|
|
39
|
+
if (bytesRead === 0) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
inputChunks.push(buffer.subarray(0, bytesRead));
|
|
43
|
+
}
|
|
44
|
+
// Assemble input into a single Uint8Array
|
|
45
|
+
const { finalBuffer } = inputChunks.reduce(
|
|
46
|
+
(context, chunk) => {
|
|
47
|
+
context.finalBuffer.set(chunk, context.bufferOffset);
|
|
48
|
+
context.bufferOffset += chunk.length;
|
|
49
|
+
return context;
|
|
50
|
+
},
|
|
51
|
+
{ bufferOffset: 0, finalBuffer: new Uint8Array(totalBytes) }
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
return JSON.parse(new TextDecoder().decode(finalBuffer));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Write output to stdout
|
|
58
|
+
function writeOutput(output) {
|
|
59
|
+
const encodedOutput = new TextEncoder().encode(JSON.stringify(output));
|
|
60
|
+
const buffer = new Uint8Array(encodedOutput);
|
|
61
|
+
// Stdout file descriptor
|
|
62
|
+
const fd = 1;
|
|
63
|
+
Javy.IO.writeSync(fd, buffer);
|
|
64
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const inquirer = require('inquirer');
|
|
2
|
+
const { getConfigJson, updateConfigJson } = require('../utils/file');
|
|
3
|
+
|
|
4
|
+
async function requestAppSecretWhenNotExist() {
|
|
5
|
+
const config = getConfigJson();
|
|
6
|
+
if (!config.appId || !config.appSecret) {
|
|
7
|
+
const { appId, appSecret } = await inquirer.prompt([
|
|
8
|
+
{
|
|
9
|
+
type: 'input',
|
|
10
|
+
name: 'appId',
|
|
11
|
+
message: 'Enter client id of app:',
|
|
12
|
+
prefix: '*'
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
type: 'input',
|
|
16
|
+
name: 'appSecret',
|
|
17
|
+
message: 'Enter client secret of app:',
|
|
18
|
+
prefix: '*'
|
|
19
|
+
}
|
|
20
|
+
]);
|
|
21
|
+
config.appId = appId;
|
|
22
|
+
config.appSecret = appSecret;
|
|
23
|
+
updateConfigJson(config);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
requestAppSecretWhenNotExist
|
|
29
|
+
};
|
package/lib/openAPI/api.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
2
|
const FormData = require('form-data');
|
|
3
|
-
const { getThemeFilenameTypeAndLocation } = require('../utils');
|
|
3
|
+
const { getThemeFilenameTypeAndLocation } = require('../utils/utils');
|
|
4
4
|
const openAPI = require('./index');
|
|
5
5
|
|
|
6
6
|
exports.getShopDetail = (config = {}) => {
|
package/lib/openAPI/index.js
CHANGED
|
@@ -3,7 +3,6 @@ const fs = require('fs-extra');
|
|
|
3
3
|
const chalk = require('chalk');
|
|
4
4
|
const Sentry = require('@sentry/node');
|
|
5
5
|
const { get, set } = require('../db/user');
|
|
6
|
-
const { getThemeFilenameTypeAndLocation } = require('../utils');
|
|
7
6
|
const { postExchangeToken } = require('../auth');
|
|
8
7
|
const log = require('../log');
|
|
9
8
|
|
|
@@ -12,17 +11,23 @@ const openAPI = axios.create({
|
|
|
12
11
|
headers: { 'Access-Token': get('exchange_token') }
|
|
13
12
|
});
|
|
14
13
|
|
|
15
|
-
openAPI.interceptors.request.use(
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
openAPI.interceptors.request.use(
|
|
15
|
+
(config) => {
|
|
16
|
+
if (!get('store_domain')) {
|
|
17
|
+
log.error(
|
|
18
|
+
chalk.red(
|
|
19
|
+
`\n✗ No store found. Please run ${chalk.cyan('shoplazza login --store STORE')} to login to a specific store`
|
|
20
|
+
)
|
|
21
|
+
);
|
|
22
|
+
process.exit(-1);
|
|
23
|
+
}
|
|
24
|
+
return config;
|
|
25
|
+
},
|
|
26
|
+
(error) => {
|
|
27
|
+
console.error(chalk.red(`[REQUEST ERROR] ${error.message}`));
|
|
28
|
+
return Promise.reject(error);
|
|
23
29
|
}
|
|
24
|
-
|
|
25
|
-
});
|
|
30
|
+
);
|
|
26
31
|
|
|
27
32
|
openAPI.interceptors.response.use(
|
|
28
33
|
function (response) {
|
|
@@ -39,6 +44,11 @@ openAPI.interceptors.response.use(
|
|
|
39
44
|
return openAPI(error.config);
|
|
40
45
|
});
|
|
41
46
|
}
|
|
47
|
+
error.response && console.error(
|
|
48
|
+
chalk.red(
|
|
49
|
+
`[RESPONSE ERROR] ${error.response.status} ${error.response.config.baseURL}${error.response.config.url}`
|
|
50
|
+
)
|
|
51
|
+
);
|
|
42
52
|
return Promise.reject(error);
|
|
43
53
|
}
|
|
44
54
|
);
|
package/lib/oss.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const FormData = require('form-data');
|
|
5
|
+
const chalk = require('chalk');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 获取OSS上传功能,适用于上传文件到店铺的OSS服务器
|
|
9
|
+
* @param {string} accessToken - 用于认证的token
|
|
10
|
+
* @param {string} storeDomain - 店铺域名
|
|
11
|
+
* @param {string} storeDomainTips - 店铺域名为空时的提示信息
|
|
12
|
+
* @returns {{ uploadOss: (filePath: string) => Promise<string> }} 返回一个对象,包含上传文件到OSS的函数
|
|
13
|
+
* @example
|
|
14
|
+
* const { uploadOss } = useOss('your-access-token', 'your-store-domain', 'Store domain is required');
|
|
15
|
+
* const ossUrl = await uploadOss('/path/to/file.txt');
|
|
16
|
+
* console.log(ossUrl); // 输出文件的 OSS 地址
|
|
17
|
+
*/
|
|
18
|
+
function useOss(accessToken, storeDomain, storeDomainTips) {
|
|
19
|
+
const ins = axios.create({
|
|
20
|
+
headers: { 'Access-Token': accessToken }
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
ins.interceptors.request.use(
|
|
24
|
+
(config) => {
|
|
25
|
+
if (!storeDomain) {
|
|
26
|
+
console.error(
|
|
27
|
+
// chalk.red(`\n\n`)
|
|
28
|
+
chalk.red(`\n${storeDomainTips}\n`)
|
|
29
|
+
);
|
|
30
|
+
process.exit(-1);
|
|
31
|
+
}
|
|
32
|
+
if (config.url.startsWith('/checkout_extensions')) {
|
|
33
|
+
config.baseURL = `https://${storeDomain}/openapi`;
|
|
34
|
+
}
|
|
35
|
+
return config;
|
|
36
|
+
},
|
|
37
|
+
(error) => {
|
|
38
|
+
console.error(chalk.red(`[REQUEST ERROR] ${error.message}`));
|
|
39
|
+
return Promise.reject(error);
|
|
40
|
+
}
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
ins.interceptors.response.use(
|
|
44
|
+
(response) => {
|
|
45
|
+
return response.data;
|
|
46
|
+
},
|
|
47
|
+
(error) => {
|
|
48
|
+
console.log(error);
|
|
49
|
+
|
|
50
|
+
console.error(
|
|
51
|
+
chalk.red(
|
|
52
|
+
`[RESPONSE ERROR] ${error.response.status} ${error.response.config.baseURL}${error.response.config.url}`
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
return Promise.reject(error);
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 上传文件到OSS
|
|
61
|
+
* @param {string} filePath - 要上传的文件路径
|
|
62
|
+
* @returns {Promise<string>} 返回文件的 OSS 地址
|
|
63
|
+
* @throws {Error} 如果上传失败或发生未知错误,抛出错误
|
|
64
|
+
* @example
|
|
65
|
+
* const ossUrl = await uploadOss('/path/to/file.txt');
|
|
66
|
+
* console.log(ossUrl); // 输出文件的 OSS 地址
|
|
67
|
+
*/
|
|
68
|
+
async function uploadOss(filePath) {
|
|
69
|
+
let fileName = path.basename(filePath);
|
|
70
|
+
const key = 'chick-extension/' + fileName;
|
|
71
|
+
const form = new FormData();
|
|
72
|
+
const url = await ins.get(`/checkout_extensions/file/sign?key=${key}`).then(async (data) => {
|
|
73
|
+
const url = data.write_host;
|
|
74
|
+
form.append('policy', data.policy);
|
|
75
|
+
form.append('OSSAccessKeyId', data.access_id);
|
|
76
|
+
form.append('success_action_status', 200);
|
|
77
|
+
form.append('signature', data.sign);
|
|
78
|
+
form.append('x-oss-forbid-overwrite', 'true');
|
|
79
|
+
form.append('key', key);
|
|
80
|
+
form.append('file', fs.createReadStream(filePath));
|
|
81
|
+
await ins.post(`https:${url}`, form, { headers: form.getHeaders() }).catch((error) => {
|
|
82
|
+
if (error.response?.data.includes('<Code>FileAlreadyExists</Code>')) {
|
|
83
|
+
console.log(chalk.yellow('[WARN] The current file already exists, not need to upload.'));
|
|
84
|
+
return;
|
|
85
|
+
} else {
|
|
86
|
+
return Promise.reject(error);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return `${data.read_host}${data.read_host.endsWith('/') ? '' : '/'}${key}`;
|
|
90
|
+
});
|
|
91
|
+
return url;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return { uploadOss };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
module.exports = {
|
|
98
|
+
useOss
|
|
99
|
+
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
const axios = require('axios');
|
|
2
|
+
const { isDevDebug, isStgDebug } = require('../utils/env');
|
|
3
|
+
const { consoleError } = require('../utils/console');
|
|
4
|
+
const { updateConfigJson, getConfigJson } = require('../utils/file');
|
|
5
|
+
|
|
6
|
+
const baseUrl = `https://partners.${isDevDebug() ? 'dev.' : isStgDebug() ? 'stg.' : ''}shoplazza.com`;
|
|
7
|
+
|
|
8
|
+
const instance = axios.create({
|
|
9
|
+
baseURL: baseUrl + '/openapi/2024-07'
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
instance.interceptors.request.use(
|
|
13
|
+
async (config) => {
|
|
14
|
+
const extConfig = getConfigJson();
|
|
15
|
+
let token = extConfig.accessToken;
|
|
16
|
+
if (!token) {
|
|
17
|
+
token = await refreshAccessToken();
|
|
18
|
+
}
|
|
19
|
+
config.headers['Access-Token'] = token;
|
|
20
|
+
config.headers['app-client-id'] = extConfig.appId;
|
|
21
|
+
return config;
|
|
22
|
+
},
|
|
23
|
+
(error) => {
|
|
24
|
+
consoleError(`[REQUEST ERROR] ${error.message}`);
|
|
25
|
+
return Promise.reject(error);
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
instance.interceptors.response.use(
|
|
30
|
+
function (response) {
|
|
31
|
+
return response;
|
|
32
|
+
},
|
|
33
|
+
async function (error) {
|
|
34
|
+
const { config, response } = error || {};
|
|
35
|
+
if (response?.status === 403 && !config._retry) {
|
|
36
|
+
config._retry = true;
|
|
37
|
+
await refreshAccessToken();
|
|
38
|
+
return instance(config);
|
|
39
|
+
}
|
|
40
|
+
error.response &&
|
|
41
|
+
consoleError(
|
|
42
|
+
`[RESPONSE ERROR] ${error.response.status} ${error.response.config.baseURL}${error.response.config.url}`
|
|
43
|
+
);
|
|
44
|
+
return Promise.reject(error);
|
|
45
|
+
}
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
function refreshAccessToken() {
|
|
49
|
+
const extensionConfig = getConfigJson();
|
|
50
|
+
if (!extensionConfig.appId || !extensionConfig.appSecret) {
|
|
51
|
+
consoleError(`must provide 'appId' and 'appSecret' in extension.config.json `);
|
|
52
|
+
process.exit(-1);
|
|
53
|
+
}
|
|
54
|
+
return axios
|
|
55
|
+
.post(baseUrl + '/partner/oauth/token', {
|
|
56
|
+
client_id: extensionConfig.appId,
|
|
57
|
+
client_secret: extensionConfig.appSecret,
|
|
58
|
+
grant_type: 'client_credentials'
|
|
59
|
+
})
|
|
60
|
+
.then((res) => {
|
|
61
|
+
const token = res.data.access_token;
|
|
62
|
+
updateConfigJson({ accessToken: token });
|
|
63
|
+
return token;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
module.exports = instance;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const axios = require('./axios');
|
|
2
|
+
// const Aaxios = require('axios');
|
|
3
|
+
|
|
4
|
+
// const axios = Aaxios.create({
|
|
5
|
+
// baseURL: 'http://igw-traefik.internal.svc.cluster.local/service/functions-api/api/partner-openapi/2025-03',
|
|
6
|
+
// headers: {
|
|
7
|
+
// 'x-rf': 'feature-ymq',
|
|
8
|
+
// 'app-client-id': '123123'
|
|
9
|
+
// }
|
|
10
|
+
// });
|
|
11
|
+
|
|
12
|
+
function createFunctionExtension(form) {
|
|
13
|
+
return axios
|
|
14
|
+
.post('/functions', form, {
|
|
15
|
+
headers: {
|
|
16
|
+
...form.getHeaders()
|
|
17
|
+
}
|
|
18
|
+
})
|
|
19
|
+
.then((res) => res.data?.data);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function updateFunctionExtension(functionId, form) {
|
|
23
|
+
return axios
|
|
24
|
+
.patch(`/functions/${functionId}`, form, {
|
|
25
|
+
headers: {
|
|
26
|
+
...form.getHeaders()
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
.then((res) => res.data?.data);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getFunctionList(params = { page: 1, limit: 1000 }) {
|
|
33
|
+
return axios
|
|
34
|
+
.get(
|
|
35
|
+
'/functions',
|
|
36
|
+
{ params },
|
|
37
|
+
{
|
|
38
|
+
headers: {
|
|
39
|
+
'Content-Type': 'application/ x-www-form-urlencoded',
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
)
|
|
43
|
+
.then((res) => res.data?.data);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 连接App
|
|
48
|
+
*/
|
|
49
|
+
async function toConnectApp(data) {
|
|
50
|
+
return axios.post(
|
|
51
|
+
'/theme-extensions/connection',
|
|
52
|
+
{
|
|
53
|
+
extension_id: data.extensionId,
|
|
54
|
+
type: data.type || 'link'
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 应用主题插件到App
|
|
61
|
+
*/
|
|
62
|
+
async function toReleaseApp(data) {
|
|
63
|
+
return axios.post(
|
|
64
|
+
'/theme-extensions/publications',
|
|
65
|
+
{
|
|
66
|
+
extension_id: data.extensionId,
|
|
67
|
+
version_id: data.versionId,
|
|
68
|
+
type: data.type || 'enable'
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
module.exports = {
|
|
74
|
+
createFunctionExtension,
|
|
75
|
+
updateFunctionExtension,
|
|
76
|
+
getFunctionList,
|
|
77
|
+
toConnectApp,
|
|
78
|
+
toReleaseApp
|
|
79
|
+
};
|
|
@@ -6,9 +6,10 @@ function isDebug() {
|
|
|
6
6
|
|
|
7
7
|
function consoleError(...args) {
|
|
8
8
|
if (isDebug()) {
|
|
9
|
-
console.trace(args);
|
|
9
|
+
console.trace(colors.red(args));
|
|
10
|
+
} else {
|
|
11
|
+
console.log(colors.red(args.join(' ')));
|
|
10
12
|
}
|
|
11
|
-
console.log(colors.red(args.join(' ')));
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
function consoleBlue(...args) {
|