@lark-apaas/miaoda-cli 0.1.0-alpha.8825a76 → 0.1.0-alpha.bc5586f
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/dist/api/db/api.js +0 -10
- package/dist/api/db/parsers.js +1 -2
- package/dist/api/file/client.js +0 -17
- package/dist/cli/commands/shared.js +8 -3
- package/dist/cli/handlers/db/sql.js +32 -12
- package/package.json +1 -1
- package/dist/api/db/_debug_trace.js +0 -21
- package/dist/api/file/_debug_trace.js +0 -21
package/dist/api/db/api.js
CHANGED
|
@@ -5,8 +5,6 @@ exports.getSchema = getSchema;
|
|
|
5
5
|
exports.importData = importData;
|
|
6
6
|
exports.exportData = exportData;
|
|
7
7
|
const http_1 = require("../../utils/http");
|
|
8
|
-
// TODO(REMOVE-BEFORE-RELEASE): debug-only HTTP trace(详见 _debug_trace.ts)
|
|
9
|
-
const _debug_trace_1 = require("./_debug_trace");
|
|
10
8
|
const error_1 = require("../../utils/error");
|
|
11
9
|
const client_1 = require("./client");
|
|
12
10
|
// CLI 不再为 dbBranch 设默认值:
|
|
@@ -26,9 +24,7 @@ async function execSql(opts) {
|
|
|
26
24
|
const url = (0, client_1.buildInnerUrl)(opts.appId, "/db/sql", {
|
|
27
25
|
dbBranch: opts.dbBranch,
|
|
28
26
|
});
|
|
29
|
-
(0, _debug_trace_1.traceRequest)("POST", url);
|
|
30
27
|
const response = await client.post(url, { sql: opts.sql });
|
|
31
|
-
(0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
|
|
32
28
|
if (!response.ok) {
|
|
33
29
|
// 4xx / 5xx:尝试解析 body 取 status_code 映射业务错误
|
|
34
30
|
let body = null;
|
|
@@ -61,9 +57,7 @@ async function getSchema(opts) {
|
|
|
61
57
|
includeStats: opts.includeStats ? "true" : undefined,
|
|
62
58
|
dbBranch: opts.dbBranch,
|
|
63
59
|
});
|
|
64
|
-
(0, _debug_trace_1.traceRequest)("GET", url);
|
|
65
60
|
const response = await client.get(url);
|
|
66
|
-
(0, _debug_trace_1.traceResponse)("GET", url, response.status, response.headers);
|
|
67
61
|
if (!response.ok) {
|
|
68
62
|
let body = null;
|
|
69
63
|
try {
|
|
@@ -95,14 +89,12 @@ async function importData(opts) {
|
|
|
95
89
|
});
|
|
96
90
|
const contentType = opts.format === "csv" ? "text/csv" : "application/json";
|
|
97
91
|
const ab = opts.body.buffer.slice(opts.body.byteOffset, opts.body.byteOffset + opts.body.byteLength);
|
|
98
|
-
(0, _debug_trace_1.traceRequest)("POST", url);
|
|
99
92
|
const response = await client.request({
|
|
100
93
|
method: "POST",
|
|
101
94
|
url,
|
|
102
95
|
headers: { "Content-Type": contentType },
|
|
103
96
|
body: ab,
|
|
104
97
|
});
|
|
105
|
-
(0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
|
|
106
98
|
if (!response.ok) {
|
|
107
99
|
let body = null;
|
|
108
100
|
try {
|
|
@@ -139,9 +131,7 @@ async function exportData(opts) {
|
|
|
139
131
|
dbBranch: opts.dbBranch,
|
|
140
132
|
});
|
|
141
133
|
const reqBody = { limit: opts.limit ?? 5000 };
|
|
142
|
-
(0, _debug_trace_1.traceRequest)("POST", url);
|
|
143
134
|
const response = await client.post(url, reqBody);
|
|
144
|
-
(0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
|
|
145
135
|
if (!response.ok) {
|
|
146
136
|
// 错误路径:body 是 JSON envelope
|
|
147
137
|
let body = null;
|
package/dist/api/db/parsers.js
CHANGED
|
@@ -27,11 +27,10 @@ function parseSqlResult(r) {
|
|
|
27
27
|
recordCount: r.recordCount ?? rows.length,
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
if (r.sqlType === "
|
|
30
|
+
if (r.sqlType === "DML") {
|
|
31
31
|
const affected = r.affectedRows ?? extractRowCount(r.data);
|
|
32
32
|
return {
|
|
33
33
|
kind: "dml",
|
|
34
|
-
sqlType: r.sqlType,
|
|
35
34
|
affectedRows: affected,
|
|
36
35
|
};
|
|
37
36
|
}
|
package/dist/api/file/client.js
CHANGED
|
@@ -8,8 +8,6 @@ exports.doPost = doPost;
|
|
|
8
8
|
exports.doRequest = doRequest;
|
|
9
9
|
const http_1 = require("../../utils/http");
|
|
10
10
|
const error_1 = require("../../utils/error");
|
|
11
|
-
// TODO(REMOVE-BEFORE-RELEASE): debug-only HTTP trace(详见 _debug_trace.ts)
|
|
12
|
-
const _debug_trace_1 = require("./_debug_trace");
|
|
13
11
|
const http_client_1 = require("@lark-apaas/http-client");
|
|
14
12
|
/** 进程内 bucket 缓存:{appId: bucketId}。不跨进程。 */
|
|
15
13
|
const bucketCache = new Map();
|
|
@@ -133,15 +131,10 @@ async function mapHttpError(err, opts) {
|
|
|
133
131
|
*/
|
|
134
132
|
async function doGet(url, opts = {}, client = (0, http_1.getHttpClient)()) {
|
|
135
133
|
try {
|
|
136
|
-
(0, _debug_trace_1.traceRequest)("GET", url);
|
|
137
134
|
const response = await client.get(url);
|
|
138
|
-
(0, _debug_trace_1.traceResponse)("GET", url, response.status, response.headers);
|
|
139
135
|
return (await response.json());
|
|
140
136
|
}
|
|
141
137
|
catch (err) {
|
|
142
|
-
if (err instanceof http_client_1.HttpError && err.response) {
|
|
143
|
-
(0, _debug_trace_1.traceResponse)("GET", url, err.response.status, err.response.headers);
|
|
144
|
-
}
|
|
145
138
|
await mapHttpError(err, opts);
|
|
146
139
|
throw err; // 不可达,mapHttpError 必定 throw
|
|
147
140
|
}
|
|
@@ -149,15 +142,10 @@ async function doGet(url, opts = {}, client = (0, http_1.getHttpClient)()) {
|
|
|
149
142
|
/** 包一层 client.post + HttpError 统一映射。默认 admin innerapi,可显式切 runtime。 */
|
|
150
143
|
async function doPost(url, body, opts = {}, client = (0, http_1.getHttpClient)()) {
|
|
151
144
|
try {
|
|
152
|
-
(0, _debug_trace_1.traceRequest)("POST", url);
|
|
153
145
|
const response = await client.post(url, body);
|
|
154
|
-
(0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
|
|
155
146
|
return (await response.json());
|
|
156
147
|
}
|
|
157
148
|
catch (err) {
|
|
158
|
-
if (err instanceof http_client_1.HttpError && err.response) {
|
|
159
|
-
(0, _debug_trace_1.traceResponse)("POST", url, err.response.status, err.response.headers);
|
|
160
|
-
}
|
|
161
149
|
await mapHttpError(err, opts);
|
|
162
150
|
throw err;
|
|
163
151
|
}
|
|
@@ -165,15 +153,10 @@ async function doPost(url, body, opts = {}, client = (0, http_1.getHttpClient)()
|
|
|
165
153
|
/** 包一层 client.request + HttpError 统一映射(DELETE 带 body 的场景)。 */
|
|
166
154
|
async function doRequest(cfg, opts = {}, client = (0, http_1.getHttpClient)()) {
|
|
167
155
|
try {
|
|
168
|
-
(0, _debug_trace_1.traceRequest)(cfg.method, cfg.url);
|
|
169
156
|
const response = await client.request(cfg);
|
|
170
|
-
(0, _debug_trace_1.traceResponse)(cfg.method, cfg.url, response.status, response.headers);
|
|
171
157
|
return (await response.json());
|
|
172
158
|
}
|
|
173
159
|
catch (err) {
|
|
174
|
-
if (err instanceof http_client_1.HttpError && err.response) {
|
|
175
|
-
(0, _debug_trace_1.traceResponse)(cfg.method, cfg.url, err.response.status, err.response.headers);
|
|
176
|
-
}
|
|
177
160
|
await mapHttpError(err, opts);
|
|
178
161
|
throw err;
|
|
179
162
|
}
|
|
@@ -7,7 +7,9 @@ exports.withHelp = withHelp;
|
|
|
7
7
|
exports.failArgs = failArgs;
|
|
8
8
|
const commander_1 = require("commander");
|
|
9
9
|
const error_1 = require("../../utils/error");
|
|
10
|
-
/** --app-id option,需要应用上下文的命令自行 .addOption(appIdOption())
|
|
10
|
+
/** --app-id option,需要应用上下文的命令自行 .addOption(appIdOption())。
|
|
11
|
+
* Commander 的 .env() 只接受单个变量名,第二个兜底 `app_id` 在 resolveAppId 里手动检查。
|
|
12
|
+
*/
|
|
11
13
|
function appIdOption() {
|
|
12
14
|
return new commander_1.Option("--app-id <id>", "指定目标应用").env("MIAODA_APP_ID");
|
|
13
15
|
}
|
|
@@ -17,9 +19,12 @@ function appIdOption() {
|
|
|
17
19
|
function softRequiredOption(name, desc) {
|
|
18
20
|
return new commander_1.Option(name, desc);
|
|
19
21
|
}
|
|
20
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* 解析 appId,优先级:CLI flag > MIAODA_APP_ID > app_id > 抛错。
|
|
24
|
+
* app_id 是部分外部沙箱环境注入应用 ID 的别名,作为兜底兼容(小写下划线形态)。
|
|
25
|
+
*/
|
|
21
26
|
function resolveAppId(opts) {
|
|
22
|
-
const id = opts.appId ?? process.env.MIAODA_APP_ID;
|
|
27
|
+
const id = opts.appId ?? process.env.MIAODA_APP_ID ?? process.env.app_id;
|
|
23
28
|
if (!id) {
|
|
24
29
|
throw new error_1.AppError("APP_ID_MISSING", "未指定应用", {
|
|
25
30
|
next_actions: [
|
|
@@ -80,7 +80,7 @@ async function handleDbSql(query, opts) {
|
|
|
80
80
|
}
|
|
81
81
|
// 其他场景:展示最后一条
|
|
82
82
|
const last = results[results.length - 1];
|
|
83
|
-
renderSingle(last);
|
|
83
|
+
renderSingle(last, sql);
|
|
84
84
|
}
|
|
85
85
|
/** 读取 stdin 并返回完整 SQL 文本(stdin 不是 TTY 即认为被 pipe)。 */
|
|
86
86
|
async function readSql(inline) {
|
|
@@ -101,11 +101,11 @@ async function readSql(inline) {
|
|
|
101
101
|
process.stdin.on("error", reject);
|
|
102
102
|
});
|
|
103
103
|
}
|
|
104
|
-
function renderSingle(raw) {
|
|
104
|
+
function renderSingle(raw, originalSql) {
|
|
105
105
|
const parsed = (0, index_1.parseSqlResult)(raw);
|
|
106
106
|
const tty = (0, render_1.isStdoutTty)();
|
|
107
107
|
if ((0, output_1.isJsonMode)()) {
|
|
108
|
-
(0, output_1.emit)(toJson(parsed));
|
|
108
|
+
(0, output_1.emit)(toJson(parsed, originalSql));
|
|
109
109
|
return;
|
|
110
110
|
}
|
|
111
111
|
if (parsed.kind === "select") {
|
|
@@ -119,7 +119,7 @@ function renderSingle(raw) {
|
|
|
119
119
|
return;
|
|
120
120
|
}
|
|
121
121
|
if (parsed.kind === "dml") {
|
|
122
|
-
const verb = dmlVerb(
|
|
122
|
+
const verb = dmlVerb(originalSql);
|
|
123
123
|
(0, output_1.emit)(tty
|
|
124
124
|
? `✓ ${String(parsed.affectedRows)} row${parsed.affectedRows === 1 ? "" : "s"} ${verb}`
|
|
125
125
|
: `OK ${String(parsed.affectedRows)} rows ${verb}`);
|
|
@@ -128,26 +128,46 @@ function renderSingle(raw) {
|
|
|
128
128
|
// DDL
|
|
129
129
|
(0, output_1.emit)(tty ? "✓ DDL executed" : "OK DDL executed");
|
|
130
130
|
}
|
|
131
|
-
function toJson(parsed) {
|
|
131
|
+
function toJson(parsed, originalSql) {
|
|
132
132
|
if (parsed.kind === "select") {
|
|
133
133
|
return { data: parsed.rows };
|
|
134
134
|
}
|
|
135
135
|
if (parsed.kind === "dml") {
|
|
136
|
+
const op = dmlOp(originalSql);
|
|
136
137
|
return {
|
|
137
138
|
data: {
|
|
138
|
-
sql_type:
|
|
139
|
+
sql_type: op ?? "dml",
|
|
139
140
|
affected_rows: parsed.affectedRows,
|
|
140
141
|
},
|
|
141
142
|
};
|
|
142
143
|
}
|
|
143
144
|
return { data: { sql_type: "ddl" } };
|
|
144
145
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
146
|
+
/**
|
|
147
|
+
* 从原始 SQL 推断 DML 动词。后端只回 "DML" 笼统类型,要给用户展示具体
|
|
148
|
+
* "inserted/updated/deleted" 必须 CLI 侧解析。多语句时取最后一条非空
|
|
149
|
+
* statement(与 PRD "只展示最后一条结果" 对齐)。
|
|
150
|
+
*/
|
|
151
|
+
function dmlOp(originalSql) {
|
|
152
|
+
const stmts = originalSql.split(";").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
153
|
+
const head = (stmts[stmts.length - 1] ?? "").toUpperCase();
|
|
154
|
+
if (head.startsWith("INSERT"))
|
|
155
|
+
return "insert";
|
|
156
|
+
if (head.startsWith("UPDATE"))
|
|
157
|
+
return "update";
|
|
158
|
+
if (head.startsWith("DELETE"))
|
|
159
|
+
return "delete";
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
function dmlVerb(originalSql) {
|
|
163
|
+
const op = dmlOp(originalSql);
|
|
164
|
+
if (op === "insert")
|
|
165
|
+
return "inserted";
|
|
166
|
+
if (op === "update")
|
|
167
|
+
return "updated";
|
|
168
|
+
if (op === "delete")
|
|
169
|
+
return "deleted";
|
|
170
|
+
return "affected";
|
|
151
171
|
}
|
|
152
172
|
/** 从第一行收集列顺序;缺失列保留空白(兼容稀疏行)。 */
|
|
153
173
|
function collectColumns(rows) {
|
package/package.json
CHANGED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.traceRequest = traceRequest;
|
|
4
|
-
exports.traceResponse = traceResponse;
|
|
5
|
-
/**
|
|
6
|
-
* ⚠️ TODO(REMOVE-BEFORE-RELEASE): 调试用 HTTP trace。
|
|
7
|
-
*
|
|
8
|
-
* 仅在 `--verbose` 下把 db 域 admin-inner 请求的 URL 与后端 logid 打到 stderr,
|
|
9
|
-
* 方便联调时把 logid 贴给后端查链路。正式版本前请整文件删除,并把
|
|
10
|
-
* `src/api/db/{api,client}.ts` 里的 `traceRequest()` / `traceResponse()` 调用一并移除。
|
|
11
|
-
*/
|
|
12
|
-
const logger_1 = require("../../utils/logger");
|
|
13
|
-
/** 请求前打 method + 完整 URL(不含敏感 header)。 */
|
|
14
|
-
function traceRequest(method, url) {
|
|
15
|
-
(0, logger_1.debug)(`http → ${method} ${url}`);
|
|
16
|
-
}
|
|
17
|
-
/** 响应后打 status + x-tt-logid(后端追踪 ID)。 */
|
|
18
|
-
function traceResponse(method, url, status, headers) {
|
|
19
|
-
const logId = headers?.get("x-tt-logid") ?? headers?.get("X-Tt-Logid") ?? "(none)";
|
|
20
|
-
(0, logger_1.debug)(`http ← ${method} ${url} status=${String(status)} x-tt-logid=${logId}`);
|
|
21
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.traceRequest = traceRequest;
|
|
4
|
-
exports.traceResponse = traceResponse;
|
|
5
|
-
/**
|
|
6
|
-
* ⚠️ TODO(REMOVE-BEFORE-RELEASE): 调试用 HTTP trace。
|
|
7
|
-
*
|
|
8
|
-
* 仅在 `--verbose` 下把 file 域请求的 URL 与后端 logid 打到 stderr,
|
|
9
|
-
* 方便联调时把 logid 贴给后端查链路。正式版本前请整文件删除,并把
|
|
10
|
-
* `src/api/file/client.ts` 里的 `traceRequest()` / `traceResponse()` 调用一并移除。
|
|
11
|
-
*/
|
|
12
|
-
const logger_1 = require("../../utils/logger");
|
|
13
|
-
/** 请求前打 method + 完整 URL(不含敏感 header)。 */
|
|
14
|
-
function traceRequest(method, url) {
|
|
15
|
-
(0, logger_1.debug)(`http → ${method} ${url}`);
|
|
16
|
-
}
|
|
17
|
-
/** 响应后打 status + x-tt-logid(后端追踪 ID)。 */
|
|
18
|
-
function traceResponse(method, url, status, headers) {
|
|
19
|
-
const logId = headers?.get("x-tt-logid") ?? headers?.get("X-Tt-Logid") ?? "(none)";
|
|
20
|
-
(0, logger_1.debug)(`http ← ${method} ${url} status=${String(status)} x-tt-logid=${logId}`);
|
|
21
|
-
}
|