byteplan-cli 1.2.0 → 1.3.0
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/package.json +1 -1
- package/src/api.js +83 -23
- package/src/cli.js +8 -1
package/package.json
CHANGED
package/src/api.js
CHANGED
|
@@ -6,7 +6,7 @@ import Conf from 'conf';
|
|
|
6
6
|
import dotenv from 'dotenv';
|
|
7
7
|
import { homedir } from 'os';
|
|
8
8
|
import { join } from 'path';
|
|
9
|
-
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
9
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
|
|
10
10
|
|
|
11
11
|
const configDir = join(homedir(), '.byteplan');
|
|
12
12
|
const envFile = join(configDir, '.env');
|
|
@@ -38,6 +38,30 @@ const DEFAULT_MENU_HEADERS = {
|
|
|
38
38
|
let currentEnv = process.env.BP_ENV || 'uat';
|
|
39
39
|
let currentToken = process.env.ACCESS_TOKEN || null;
|
|
40
40
|
|
|
41
|
+
// 统一的响应处理函数
|
|
42
|
+
async function handleResponse(response) {
|
|
43
|
+
const data = await response.json();
|
|
44
|
+
|
|
45
|
+
// 检查 HTTP 状态码
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
// 401 表示 token 无效或过期
|
|
48
|
+
if (response.status === 401) {
|
|
49
|
+
throw new Error('Token invalid or expired. Please run "byteplan login" to re-authenticate.');
|
|
50
|
+
}
|
|
51
|
+
// 其他 HTTP 错误
|
|
52
|
+
const errMsg = data.message || data.error_description || data.msg || `HTTP ${response.status}`;
|
|
53
|
+
throw new Error('API error: ' + errMsg);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 检查响应中的错误字段(有些 API 返回 200 但包含错误信息)
|
|
57
|
+
if (data.error || data.code === 'ERROR' || data.success === false) {
|
|
58
|
+
const errMsg = data.message || data.msg || data.error_description || JSON.stringify(data);
|
|
59
|
+
throw new Error('API error: ' + errMsg);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
|
|
41
65
|
export function setEnvironment(env) {
|
|
42
66
|
if (ENVIRONMENTS[env]) {
|
|
43
67
|
currentEnv = env;
|
|
@@ -87,7 +111,7 @@ export async function getPublicKey() {
|
|
|
87
111
|
// 保存凭证到 .env
|
|
88
112
|
function saveCredentials(data) {
|
|
89
113
|
const envPath = join(homedir(), '.byteplan', '.env');
|
|
90
|
-
|
|
114
|
+
|
|
91
115
|
const lines = [];
|
|
92
116
|
lines.push('BP_ENV=' + currentEnv);
|
|
93
117
|
lines.push('BP_USER=' + data.username);
|
|
@@ -101,10 +125,42 @@ function saveCredentials(data) {
|
|
|
101
125
|
if (data.expiresIn) {
|
|
102
126
|
lines.push('TOKEN_EXPIRES_IN=' + (Date.now() + data.expiresIn * 1000));
|
|
103
127
|
}
|
|
104
|
-
|
|
128
|
+
|
|
105
129
|
writeFileSync(envPath, lines.join('\n') + '\n');
|
|
106
130
|
}
|
|
107
131
|
|
|
132
|
+
// 保存 token 到 .env(切换租户时使用)
|
|
133
|
+
export function saveToken(accessToken, refreshToken, expiresIn) {
|
|
134
|
+
const envPath = join(homedir(), '.byteplan', '.env');
|
|
135
|
+
|
|
136
|
+
// 读取现有的 .env 内容
|
|
137
|
+
let existingLines = [];
|
|
138
|
+
if (existsSync(envPath)) {
|
|
139
|
+
existingLines = readFileSync(envPath, 'utf-8').split('\n').filter(line =>
|
|
140
|
+
!line.startsWith('ACCESS_TOKEN=') &&
|
|
141
|
+
!line.startsWith('REFRESH_TOKEN=') &&
|
|
142
|
+
!line.startsWith('TOKEN_EXPIRES_IN=')
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 添加新的 token 信息
|
|
147
|
+
const newLines = [...existingLines];
|
|
148
|
+
if (accessToken) {
|
|
149
|
+
newLines.push('ACCESS_TOKEN=' + accessToken);
|
|
150
|
+
}
|
|
151
|
+
if (refreshToken) {
|
|
152
|
+
newLines.push('REFRESH_TOKEN=' + refreshToken);
|
|
153
|
+
}
|
|
154
|
+
if (expiresIn) {
|
|
155
|
+
newLines.push('TOKEN_EXPIRES_IN=' + (Date.now() + expiresIn * 1000));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
writeFileSync(envPath, newLines.join('\n') + '\n');
|
|
159
|
+
|
|
160
|
+
// 更新内存中的 token
|
|
161
|
+
setToken(accessToken);
|
|
162
|
+
}
|
|
163
|
+
|
|
108
164
|
// 登录
|
|
109
165
|
export async function login(username, password, env = 'uat') {
|
|
110
166
|
if (env) setEnvironment(env);
|
|
@@ -212,8 +268,8 @@ export async function getUserInfo(token) {
|
|
|
212
268
|
'authorization': 'Bearer ' + (token || currentToken),
|
|
213
269
|
},
|
|
214
270
|
});
|
|
215
|
-
|
|
216
|
-
return response
|
|
271
|
+
|
|
272
|
+
return handleResponse(response);
|
|
217
273
|
}
|
|
218
274
|
|
|
219
275
|
// 切换租户
|
|
@@ -227,27 +283,27 @@ export async function switchTenant(token, tenantId) {
|
|
|
227
283
|
'authorization': 'Bearer ' + (token || currentToken),
|
|
228
284
|
},
|
|
229
285
|
});
|
|
230
|
-
|
|
231
|
-
return response
|
|
286
|
+
|
|
287
|
+
return handleResponse(response);
|
|
232
288
|
}
|
|
233
289
|
|
|
234
290
|
// 查询模型列表
|
|
235
291
|
export async function queryModels(token, options = {}) {
|
|
236
292
|
const { page = 0, size = 100 } = options;
|
|
237
293
|
const baseUrl = getBaseUrl();
|
|
238
|
-
|
|
294
|
+
|
|
239
295
|
const headers = {
|
|
240
296
|
'accept': 'application/json, text/plain, */*',
|
|
241
297
|
'authorization': 'Bearer ' + (token || currentToken),
|
|
242
298
|
...DEFAULT_MENU_HEADERS,
|
|
243
299
|
};
|
|
244
|
-
|
|
300
|
+
|
|
245
301
|
const response = await fetch(baseUrl + '/data/api/model/query?page=' + page + '&size=' + size, {
|
|
246
302
|
method: 'GET',
|
|
247
303
|
headers,
|
|
248
304
|
});
|
|
249
|
-
|
|
250
|
-
return response
|
|
305
|
+
|
|
306
|
+
return handleResponse(response);
|
|
251
307
|
}
|
|
252
308
|
|
|
253
309
|
// 获取模型字段
|
|
@@ -263,8 +319,8 @@ export async function getModelColumns(token, modelCodes) {
|
|
|
263
319
|
},
|
|
264
320
|
body: JSON.stringify(modelCodes),
|
|
265
321
|
});
|
|
266
|
-
|
|
267
|
-
return response
|
|
322
|
+
|
|
323
|
+
return handleResponse(response);
|
|
268
324
|
}
|
|
269
325
|
|
|
270
326
|
// 查询模型数据
|
|
@@ -280,18 +336,22 @@ export async function getModelData(token, modelCode, params = {}) {
|
|
|
280
336
|
},
|
|
281
337
|
body: JSON.stringify({
|
|
282
338
|
modelCode,
|
|
283
|
-
|
|
339
|
+
params: {
|
|
340
|
+
pageNum: params.pageNum || 0,
|
|
341
|
+
pageSize: params.pageSize || 100,
|
|
342
|
+
...params,
|
|
343
|
+
},
|
|
284
344
|
}),
|
|
285
345
|
});
|
|
286
|
-
|
|
287
|
-
return response
|
|
346
|
+
|
|
347
|
+
return handleResponse(response);
|
|
288
348
|
}
|
|
289
349
|
|
|
290
350
|
// 获取维度值
|
|
291
351
|
export async function getDimValues(token, dimCode, options = {}) {
|
|
292
352
|
const { page = 0, size = 100 } = options;
|
|
293
353
|
const baseUrl = getBaseUrl();
|
|
294
|
-
|
|
354
|
+
|
|
295
355
|
const response = await fetch(baseUrl + '/data/api/online/lov/DATA_DIM_VALUE_LOV?dimCode=' + dimCode + '&page=' + page + '&size=' + size, {
|
|
296
356
|
method: 'POST',
|
|
297
357
|
headers: {
|
|
@@ -302,18 +362,18 @@ export async function getDimValues(token, dimCode, options = {}) {
|
|
|
302
362
|
},
|
|
303
363
|
body: JSON.stringify({ dimCode, page, size }),
|
|
304
364
|
});
|
|
305
|
-
|
|
306
|
-
return response
|
|
365
|
+
|
|
366
|
+
return handleResponse(response);
|
|
307
367
|
}
|
|
308
368
|
|
|
309
369
|
// 获取 LOV 值
|
|
310
370
|
export async function getLovValues(token, lovCode, options = {}) {
|
|
311
371
|
const { keywords = null } = options;
|
|
312
372
|
const baseUrl = getBaseUrl();
|
|
313
|
-
|
|
373
|
+
|
|
314
374
|
const body = {};
|
|
315
375
|
if (keywords) body.keywords = keywords;
|
|
316
|
-
|
|
376
|
+
|
|
317
377
|
const response = await fetch(baseUrl + '/data/api/online/lov/' + lovCode, {
|
|
318
378
|
method: 'POST',
|
|
319
379
|
headers: {
|
|
@@ -324,6 +384,6 @@ export async function getLovValues(token, lovCode, options = {}) {
|
|
|
324
384
|
},
|
|
325
385
|
body: JSON.stringify(body),
|
|
326
386
|
});
|
|
327
|
-
|
|
328
|
-
return response
|
|
387
|
+
|
|
388
|
+
return handleResponse(response);
|
|
329
389
|
}
|
package/src/cli.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
getModelData,
|
|
17
17
|
getDimValues,
|
|
18
18
|
getLovValues,
|
|
19
|
+
saveToken,
|
|
19
20
|
} from './api.js';
|
|
20
21
|
import { skillsCmd } from './commands/skills.js';
|
|
21
22
|
|
|
@@ -141,12 +142,18 @@ tenantCmd
|
|
|
141
142
|
await loginWithEnv();
|
|
142
143
|
const result = await switchTenant(null, tenantId);
|
|
143
144
|
|
|
145
|
+
// 保存切换后的新 token
|
|
146
|
+
if (result.access_token) {
|
|
147
|
+
saveToken(result.access_token, result.refresh_token, result.expires_in);
|
|
148
|
+
}
|
|
149
|
+
|
|
144
150
|
printJSON({
|
|
145
151
|
success: true,
|
|
146
152
|
tenant: {
|
|
147
153
|
tenantId: tenantId,
|
|
148
154
|
tenantName: result.data?.tenantName || '',
|
|
149
155
|
},
|
|
156
|
+
tokenUpdated: !!result.access_token,
|
|
150
157
|
});
|
|
151
158
|
} catch (error) {
|
|
152
159
|
printError(error);
|
|
@@ -229,7 +236,7 @@ const dataCmd = program
|
|
|
229
236
|
dataCmd
|
|
230
237
|
.command('query <modelCode>')
|
|
231
238
|
.description('Query data from a model')
|
|
232
|
-
.option('-p, --page <number>', 'Page number', '0')
|
|
239
|
+
.option('-p, --page <number>', 'Page number (starting from 0)', '0')
|
|
233
240
|
.option('-s, --size <number>', 'Page size', '100')
|
|
234
241
|
.action(async (modelCode, options) => {
|
|
235
242
|
try {
|