@lark-apaas/miaoda-cli 0.1.0-alpha.36c401b → 0.1.0-alpha.8825a76

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.
@@ -0,0 +1,21 @@
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
+ }
@@ -5,6 +5,8 @@ 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");
8
10
  const error_1 = require("../../utils/error");
9
11
  const client_1 = require("./client");
10
12
  // CLI 不再为 dbBranch 设默认值:
@@ -24,7 +26,9 @@ async function execSql(opts) {
24
26
  const url = (0, client_1.buildInnerUrl)(opts.appId, "/db/sql", {
25
27
  dbBranch: opts.dbBranch,
26
28
  });
29
+ (0, _debug_trace_1.traceRequest)("POST", url);
27
30
  const response = await client.post(url, { sql: opts.sql });
31
+ (0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
28
32
  if (!response.ok) {
29
33
  // 4xx / 5xx:尝试解析 body 取 status_code 映射业务错误
30
34
  let body = null;
@@ -57,7 +61,9 @@ async function getSchema(opts) {
57
61
  includeStats: opts.includeStats ? "true" : undefined,
58
62
  dbBranch: opts.dbBranch,
59
63
  });
64
+ (0, _debug_trace_1.traceRequest)("GET", url);
60
65
  const response = await client.get(url);
66
+ (0, _debug_trace_1.traceResponse)("GET", url, response.status, response.headers);
61
67
  if (!response.ok) {
62
68
  let body = null;
63
69
  try {
@@ -89,12 +95,14 @@ async function importData(opts) {
89
95
  });
90
96
  const contentType = opts.format === "csv" ? "text/csv" : "application/json";
91
97
  const ab = opts.body.buffer.slice(opts.body.byteOffset, opts.body.byteOffset + opts.body.byteLength);
98
+ (0, _debug_trace_1.traceRequest)("POST", url);
92
99
  const response = await client.request({
93
100
  method: "POST",
94
101
  url,
95
102
  headers: { "Content-Type": contentType },
96
103
  body: ab,
97
104
  });
105
+ (0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
98
106
  if (!response.ok) {
99
107
  let body = null;
100
108
  try {
@@ -131,7 +139,9 @@ async function exportData(opts) {
131
139
  dbBranch: opts.dbBranch,
132
140
  });
133
141
  const reqBody = { limit: opts.limit ?? 5000 };
142
+ (0, _debug_trace_1.traceRequest)("POST", url);
134
143
  const response = await client.post(url, reqBody);
144
+ (0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
135
145
  if (!response.ok) {
136
146
  // 错误路径:body 是 JSON envelope
137
147
  let body = null;
@@ -0,0 +1,21 @@
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
+ }
@@ -8,6 +8,8 @@ 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");
11
13
  const http_client_1 = require("@lark-apaas/http-client");
12
14
  /** 进程内 bucket 缓存:{appId: bucketId}。不跨进程。 */
13
15
  const bucketCache = new Map();
@@ -131,10 +133,15 @@ async function mapHttpError(err, opts) {
131
133
  */
132
134
  async function doGet(url, opts = {}, client = (0, http_1.getHttpClient)()) {
133
135
  try {
136
+ (0, _debug_trace_1.traceRequest)("GET", url);
134
137
  const response = await client.get(url);
138
+ (0, _debug_trace_1.traceResponse)("GET", url, response.status, response.headers);
135
139
  return (await response.json());
136
140
  }
137
141
  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
+ }
138
145
  await mapHttpError(err, opts);
139
146
  throw err; // 不可达,mapHttpError 必定 throw
140
147
  }
@@ -142,10 +149,15 @@ async function doGet(url, opts = {}, client = (0, http_1.getHttpClient)()) {
142
149
  /** 包一层 client.post + HttpError 统一映射。默认 admin innerapi,可显式切 runtime。 */
143
150
  async function doPost(url, body, opts = {}, client = (0, http_1.getHttpClient)()) {
144
151
  try {
152
+ (0, _debug_trace_1.traceRequest)("POST", url);
145
153
  const response = await client.post(url, body);
154
+ (0, _debug_trace_1.traceResponse)("POST", url, response.status, response.headers);
146
155
  return (await response.json());
147
156
  }
148
157
  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
+ }
149
161
  await mapHttpError(err, opts);
150
162
  throw err;
151
163
  }
@@ -153,10 +165,15 @@ async function doPost(url, body, opts = {}, client = (0, http_1.getHttpClient)()
153
165
  /** 包一层 client.request + HttpError 统一映射(DELETE 带 body 的场景)。 */
154
166
  async function doRequest(cfg, opts = {}, client = (0, http_1.getHttpClient)()) {
155
167
  try {
168
+ (0, _debug_trace_1.traceRequest)(cfg.method, cfg.url);
156
169
  const response = await client.request(cfg);
170
+ (0, _debug_trace_1.traceResponse)(cfg.method, cfg.url, response.status, response.headers);
157
171
  return (await response.json());
158
172
  }
159
173
  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
+ }
160
177
  await mapHttpError(err, opts);
161
178
  throw err;
162
179
  }
@@ -114,7 +114,7 @@ function renderSingle(raw) {
114
114
  return;
115
115
  }
116
116
  const cols = collectColumns(parsed.rows);
117
- const rows = parsed.rows.map((r) => cols.map((c) => formatCell(r[c])));
117
+ const rows = parsed.rows.map((r) => cols.map((c) => formatCell(r[c], tty)));
118
118
  (0, output_1.emit)(tty ? (0, render_1.renderAlignedTable)(cols, rows) : (0, render_1.renderTsv)(cols, rows));
119
119
  return;
120
120
  }
@@ -155,9 +155,19 @@ function collectColumns(rows) {
155
155
  return [];
156
156
  return Object.keys(rows[0]);
157
157
  }
158
- function formatCell(v) {
159
- if (v === null || v === undefined)
160
- return "";
158
+ /**
159
+ * SQL 单元格 字符串:
160
+ * - null / undefined → "NULL"(TTY 下用 dim+gray ANSI 弱化,对齐 mysql/DuckDB;
161
+ * non-TTY 用裸字面量,避免被 cat / 管道吞掉样式;JSON 模式不会走到这里,
162
+ * 走 toJson 直接用 parsed.rows,JSON.stringify 输出 `null` 字面)
163
+ * - string → 原样
164
+ * - number / boolean → toString
165
+ * - object / array → JSON.stringify
166
+ */
167
+ function formatCell(v, tty) {
168
+ if (v === null || v === undefined) {
169
+ return tty ? "\u001b[2;90mNULL\u001b[0m" : "NULL";
170
+ }
161
171
  if (typeof v === "string")
162
172
  return v;
163
173
  if (typeof v === "number" || typeof v === "boolean")
@@ -14,6 +14,7 @@
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.formatSize = formatSize;
16
16
  exports.formatTime = formatTime;
17
+ exports.visibleWidth = visibleWidth;
17
18
  exports.renderAlignedTable = renderAlignedTable;
18
19
  exports.renderTsv = renderTsv;
19
20
  exports.renderKeyValue = renderKeyValue;
@@ -64,21 +65,35 @@ function formatTime(iso, isTty) {
64
65
  const da = String(date.getDate()).padStart(2, "0");
65
66
  return `${y}-${mo}-${da}`;
66
67
  }
67
- /** 渲染 TTY 对齐表格(多行,列宽按最长内容)。 */
68
+ /**
69
+ * SGR (Select Graphic Rendition) ANSI 转义匹配:`ESC[<digits;...>m`。
70
+ * 用于在列宽计算时剥离不显示的控制字符——否则带 ANSI 颜色的 cell 会按 .length
71
+ * 算进列宽(比如 dim "NULL" 实际占 4 字符但 .length=11),导致表格对齐错位。
72
+ */
73
+ const ANSI_SGR_RE = /\[[0-9;]*m/g;
74
+ /** cell 可见字符宽度:剥离 ANSI 转义后再算长度。 */
75
+ function visibleWidth(s) {
76
+ return s.replace(ANSI_SGR_RE, "").length;
77
+ }
78
+ function padVisibleEnd(s, targetWidth) {
79
+ const w = visibleWidth(s);
80
+ return w >= targetWidth ? s : s + " ".repeat(targetWidth - w);
81
+ }
82
+ /** 渲染 TTY 对齐表格(多行,列宽按最长内容;ANSI 转义不计入列宽)。 */
68
83
  function renderAlignedTable(headers, rows) {
69
84
  const colWidths = headers.map((h, i) => {
70
- let w = h.length;
85
+ let w = visibleWidth(h);
71
86
  for (const row of rows) {
72
- const cell = row[i] || "";
73
- if (cell.length > w)
74
- w = cell.length;
87
+ const cw = visibleWidth(row[i] || "");
88
+ if (cw > w)
89
+ w = cw;
75
90
  }
76
91
  return w;
77
92
  });
78
93
  const lines = [];
79
- lines.push(headers.map((h, i) => h.padEnd(colWidths[i])).join(" ").trimEnd());
94
+ lines.push(headers.map((h, i) => padVisibleEnd(h, colWidths[i])).join(" ").trimEnd());
80
95
  for (const row of rows) {
81
- lines.push(row.map((cell, i) => (cell || "").padEnd(colWidths[i])).join(" ").trimEnd());
96
+ lines.push(row.map((cell, i) => padVisibleEnd(cell || "", colWidths[i])).join(" ").trimEnd());
82
97
  }
83
98
  return lines.join("\n");
84
99
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/miaoda-cli",
3
- "version": "0.1.0-alpha.36c401b",
3
+ "version": "0.1.0-alpha.8825a76",
4
4
  "description": "Miaoda 平台命令行工具,面向 Agent 调用",
5
5
  "type": "commonjs",
6
6
  "bin": {