eprolo-cli 1.0.44 → 1.0.46
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/bin/eprolo-cli.js +106 -57
- package/package.json +1 -1
package/bin/eprolo-cli.js
CHANGED
|
@@ -4,14 +4,16 @@
|
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const os = require("os");
|
|
6
6
|
const path = require("path");
|
|
7
|
-
const
|
|
7
|
+
const https = require("https");
|
|
8
8
|
|
|
9
9
|
const LOGIN_API = "https://wixtest.eprolo.com/v1/auth/verify-code";
|
|
10
|
+
const REFRESH_API = "https://wixtest.eprolo.com/v1/auth/refresh-code";
|
|
11
|
+
const ORDERS_API = "https://wixtest.eprolo.com/test/orders";
|
|
10
12
|
const CONFIG_DIR = path.join(os.homedir(), ".eprolo-toolkit");
|
|
11
13
|
const CONFIG_FILE = path.join(CONFIG_DIR, "config.json");
|
|
12
14
|
|
|
13
15
|
// ---------------------------------------------------------------------------
|
|
14
|
-
// 凭据文件读写(~/.
|
|
16
|
+
// 凭据文件读写(~/.eprolo-toolkit/config.json)
|
|
15
17
|
// 框架判定连接成功的唯一依据:凭据文件出现
|
|
16
18
|
// 框架读顶层明文 account 字段做授权卡片标签
|
|
17
19
|
// ---------------------------------------------------------------------------
|
|
@@ -32,26 +34,6 @@ function writeConfig(config) {
|
|
|
32
34
|
// 参数解析
|
|
33
35
|
// ---------------------------------------------------------------------------
|
|
34
36
|
|
|
35
|
-
function parseArgs(argv) {
|
|
36
|
-
const args = { _: [] };
|
|
37
|
-
for (let i = 0; i < argv.length; i += 1) {
|
|
38
|
-
const token = argv[i];
|
|
39
|
-
if (!token.startsWith("--")) {
|
|
40
|
-
args._.push(token);
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
const key = token.slice(2).replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
44
|
-
const next = argv[i + 1];
|
|
45
|
-
if (!next || next.startsWith("--")) {
|
|
46
|
-
args[key] = true;
|
|
47
|
-
} else {
|
|
48
|
-
args[key] = next;
|
|
49
|
-
i += 1;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return args;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
37
|
function readFlag(argv, flag) {
|
|
56
38
|
const idx = argv.indexOf(flag);
|
|
57
39
|
if (idx === -1 || idx + 1 >= argv.length) return undefined;
|
|
@@ -59,21 +41,22 @@ function readFlag(argv, flag) {
|
|
|
59
41
|
}
|
|
60
42
|
|
|
61
43
|
// ---------------------------------------------------------------------------
|
|
62
|
-
//
|
|
44
|
+
// HTTPS POST 请求
|
|
63
45
|
// ---------------------------------------------------------------------------
|
|
64
46
|
|
|
65
|
-
function postJson(url, body) {
|
|
47
|
+
function postJson(url, body, headers = {}) {
|
|
66
48
|
return new Promise((resolve, reject) => {
|
|
67
49
|
const target = new URL(url);
|
|
68
50
|
const payload = JSON.stringify(body);
|
|
69
|
-
const req =
|
|
51
|
+
const req = https.request({
|
|
70
52
|
hostname: target.hostname,
|
|
71
|
-
port: target.port,
|
|
53
|
+
port: target.port || 443,
|
|
72
54
|
path: `${target.pathname}${target.search}`,
|
|
73
55
|
method: "POST",
|
|
74
56
|
headers: {
|
|
75
57
|
"content-type": "application/json",
|
|
76
|
-
"content-length": Buffer.byteLength(payload)
|
|
58
|
+
"content-length": Buffer.byteLength(payload),
|
|
59
|
+
...headers
|
|
77
60
|
}
|
|
78
61
|
}, (res) => {
|
|
79
62
|
const chunks = [];
|
|
@@ -86,13 +69,7 @@ function postJson(url, body) {
|
|
|
86
69
|
} catch (_) {
|
|
87
70
|
data = { raw: text };
|
|
88
71
|
}
|
|
89
|
-
|
|
90
|
-
const err = new Error(`HTTP ${res.statusCode} ${res.statusMessage || ""}`.trim());
|
|
91
|
-
err.response = data;
|
|
92
|
-
reject(err);
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
resolve(data);
|
|
72
|
+
resolve({ statusCode: res.statusCode, data });
|
|
96
73
|
});
|
|
97
74
|
});
|
|
98
75
|
req.on("error", reject);
|
|
@@ -101,32 +78,79 @@ function postJson(url, body) {
|
|
|
101
78
|
});
|
|
102
79
|
}
|
|
103
80
|
|
|
81
|
+
// ---------------------------------------------------------------------------
|
|
82
|
+
// 带 401 自动刷新 token 重试的请求
|
|
83
|
+
// 1. 发起请求
|
|
84
|
+
// 2. 如果返回 401 → 调用 refresh-code 刷新 token → 回写凭据文件 → 重试一次
|
|
85
|
+
// 3. 仍然 401 → 抛错
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
|
|
88
|
+
async function postJsonWithRetry(url, body, config) {
|
|
89
|
+
const headers = {};
|
|
90
|
+
if (config.accessToken) headers["authorization"] = `Bearer ${config.accessToken}`;
|
|
91
|
+
|
|
92
|
+
let result = await postJson(url, body, headers);
|
|
93
|
+
|
|
94
|
+
if (result.statusCode === 401) {
|
|
95
|
+
// 刷新 token
|
|
96
|
+
const refreshRes = await postJson(REFRESH_API, {
|
|
97
|
+
accessToken: config.accessToken,
|
|
98
|
+
accountId: config.accountId,
|
|
99
|
+
shopId: config.shopId
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
if (refreshRes.statusCode >= 200 && refreshRes.statusCode < 300 && refreshRes.data.accessToken) {
|
|
103
|
+
// 更新凭据文件
|
|
104
|
+
config.accessToken = refreshRes.data.accessToken;
|
|
105
|
+
if (refreshRes.data.account) config.account = refreshRes.data.account;
|
|
106
|
+
writeConfig(config);
|
|
107
|
+
|
|
108
|
+
// 用新 token 重试
|
|
109
|
+
headers["authorization"] = `Bearer ${config.accessToken}`;
|
|
110
|
+
result = await postJson(url, body, headers);
|
|
111
|
+
} else {
|
|
112
|
+
const err = new Error("Token 刷新失败,请重新登录授权");
|
|
113
|
+
err.response = refreshRes.data;
|
|
114
|
+
throw err;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (result.statusCode < 200 || result.statusCode >= 300) {
|
|
119
|
+
const err = new Error(`HTTP ${result.statusCode}`);
|
|
120
|
+
err.response = result.data;
|
|
121
|
+
throw err;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return result.data;
|
|
125
|
+
}
|
|
126
|
+
|
|
104
127
|
// ---------------------------------------------------------------------------
|
|
105
128
|
// D2 · login 命令
|
|
106
|
-
// 输入契约(框架 → CLI):
|
|
107
|
-
// userCode ← env 通道 process.env.DXB_USER_CODE
|
|
108
|
-
// defaultShop ← arg 通道 --default-shop
|
|
109
|
-
// 行为契约:
|
|
110
|
-
// 成功 → 写凭据文件 + exit 0
|
|
111
|
-
// 失败 → 非零退出 + stderr 错误信息
|
|
112
|
-
// ❌ 禁止交互式 prompt
|
|
113
129
|
// ---------------------------------------------------------------------------
|
|
114
130
|
|
|
115
131
|
async function login(argv) {
|
|
116
132
|
const userCode = process.env.EPROLO_USER_CODE; // env 通道
|
|
117
133
|
if (!userCode) { console.error("缺少用户密文:请在授权弹窗中填写"); process.exit(2); }
|
|
118
134
|
|
|
119
|
-
const defaultShop = readFlag(argv, "--default-shop");
|
|
135
|
+
const defaultShop = readFlag(argv, "--default-shop"); // arg 通道,可能不存在
|
|
120
136
|
|
|
121
|
-
const res = await
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
137
|
+
const res = await postJson(LOGIN_API, { openApiKey: userCode });
|
|
138
|
+
|
|
139
|
+
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
140
|
+
console.error(JSON.stringify({
|
|
141
|
+
success: false,
|
|
142
|
+
errorMessage: "密文验证失败,请到账号设置页重新复制",
|
|
143
|
+
statusCode: res.statusCode,
|
|
144
|
+
response: res.data
|
|
145
|
+
}));
|
|
146
|
+
process.exit(1);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const { account, accessToken, accountId, shopId } = res.data;
|
|
150
|
+
const config = { account, accessToken, defaultShop, accountId, shopId, version: 1 };
|
|
151
|
+
writeConfig(config);
|
|
126
152
|
|
|
127
|
-
|
|
128
|
-
writeConfig({ account, accessToken, defaultShop,accountId,shopId }); // → D3
|
|
129
|
-
console.log("login ok"); // 不打印任何敏感值
|
|
153
|
+
console.log("login ok");
|
|
130
154
|
process.exit(0);
|
|
131
155
|
}
|
|
132
156
|
|
|
@@ -155,33 +179,53 @@ function authLogout() {
|
|
|
155
179
|
process.exit(0);
|
|
156
180
|
}
|
|
157
181
|
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
// orders query — 查询订单(带 401 自动刷新)
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
|
|
186
|
+
async function queryOrders() {
|
|
187
|
+
const config = readConfig();
|
|
188
|
+
if (!config.accessToken) {
|
|
189
|
+
console.error(JSON.stringify({ success: false, errorMessage: "未授权,请先登录" }));
|
|
190
|
+
process.exit(1);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const data = await postJsonWithRetry(ORDERS_API, {}, config);
|
|
194
|
+
console.log(JSON.stringify(data, null, 2));
|
|
195
|
+
process.exit(0);
|
|
196
|
+
}
|
|
197
|
+
|
|
158
198
|
// ---------------------------------------------------------------------------
|
|
159
199
|
// help
|
|
160
200
|
// ---------------------------------------------------------------------------
|
|
161
201
|
|
|
162
202
|
function printHelp() {
|
|
163
|
-
console.log(`
|
|
203
|
+
console.log(`EPROLO CLI (cli-login 形态)
|
|
164
204
|
|
|
165
205
|
Usage:
|
|
166
|
-
eprolo-cli auth login [--default-shop <shop>] 登录并写凭据文件(框架通过 env 注入
|
|
206
|
+
eprolo-cli auth login [--default-shop <shop>] 登录并写凭据文件(框架通过 env 注入 EPROLO_USER_CODE)
|
|
167
207
|
eprolo-cli auth status 查看授权状态
|
|
168
208
|
eprolo-cli auth logout 退出授权
|
|
209
|
+
eprolo-cli orders 查询订单列表
|
|
169
210
|
|
|
170
211
|
Authorization:
|
|
171
212
|
框架通过 fieldInjection 把表单值递交给 CLI:
|
|
172
|
-
userCode → env 通道 → process.env.
|
|
213
|
+
userCode → env 通道 → process.env.EPROLO_USER_CODE
|
|
173
214
|
defaultShop → arg 通道 → --default-shop
|
|
174
215
|
|
|
175
|
-
连接成功的唯一判定:凭据文件 ~/.
|
|
216
|
+
连接成功的唯一判定:凭据文件 ~/.eprolo-toolkit/config.json 出现
|
|
176
217
|
凭据文件顶层明文 account 字段用于授权卡片标签
|
|
177
218
|
|
|
178
219
|
登录时调用 ${LOGIN_API} 验证密文
|
|
220
|
+
401 时自动调用 ${REFRESH_API} 刷新 token 并重试
|
|
179
221
|
|
|
180
|
-
Credential file (~/.
|
|
222
|
+
Credential file (~/.eprolo-toolkit/config.json):
|
|
181
223
|
{
|
|
182
|
-
"account": "user@example.com",
|
|
183
|
-
"
|
|
224
|
+
"account": "user@example.com",
|
|
225
|
+
"accessToken": "...",
|
|
184
226
|
"defaultShop": "shop-001",
|
|
227
|
+
"accountId": "...",
|
|
228
|
+
"shopId": "...",
|
|
185
229
|
"version": 1
|
|
186
230
|
}
|
|
187
231
|
`);
|
|
@@ -209,6 +253,11 @@ async function main() {
|
|
|
209
253
|
return;
|
|
210
254
|
}
|
|
211
255
|
|
|
256
|
+
if (argv[0] === "orders") {
|
|
257
|
+
await queryOrders();
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
212
261
|
printHelp();
|
|
213
262
|
}
|
|
214
263
|
|
package/package.json
CHANGED