@lark-apaas/miaoda-cli 0.1.2 → 0.1.3-alpha.09899c4

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.
Files changed (85) hide show
  1. package/README.md +8 -7
  2. package/dist/api/app/api.js +25 -0
  3. package/dist/api/app/index.js +15 -0
  4. package/dist/api/app/schemas.js +79 -0
  5. package/dist/api/app/types.js +58 -0
  6. package/dist/api/db/api.js +390 -55
  7. package/dist/api/db/client.js +65 -25
  8. package/dist/api/db/index.js +12 -1
  9. package/dist/api/db/parsers.js +20 -20
  10. package/dist/api/db/sql-keywords.js +87 -87
  11. package/dist/api/deploy/api.js +60 -0
  12. package/dist/api/deploy/index.js +16 -0
  13. package/dist/api/deploy/schemas.js +105 -0
  14. package/dist/api/deploy/types.js +22 -0
  15. package/dist/api/file/api.js +89 -87
  16. package/dist/api/file/client.js +62 -22
  17. package/dist/api/file/detect.js +3 -3
  18. package/dist/api/file/index.js +2 -1
  19. package/dist/api/file/parsers.js +18 -7
  20. package/dist/api/index.js +7 -1
  21. package/dist/api/observability/api.js +52 -0
  22. package/dist/api/observability/index.js +16 -0
  23. package/dist/api/observability/schemas.js +60 -0
  24. package/dist/api/observability/types.js +27 -0
  25. package/dist/api/plugin/api.js +31 -31
  26. package/dist/cli/commands/app/index.js +62 -0
  27. package/dist/cli/commands/db/index.js +600 -59
  28. package/dist/cli/commands/deploy/index.js +155 -0
  29. package/dist/cli/commands/file/index.js +91 -63
  30. package/dist/cli/commands/index.js +10 -6
  31. package/dist/cli/commands/observability/index.js +240 -0
  32. package/dist/cli/commands/plugin/index.js +27 -27
  33. package/dist/cli/commands/shared.js +86 -10
  34. package/dist/cli/handlers/app/get.js +47 -0
  35. package/dist/cli/handlers/app/index.js +7 -0
  36. package/dist/cli/handlers/app/update.js +59 -0
  37. package/dist/cli/handlers/db/_operator.js +35 -0
  38. package/dist/cli/handlers/db/audit.js +383 -0
  39. package/dist/cli/handlers/db/changelog.js +160 -0
  40. package/dist/cli/handlers/db/data.js +34 -34
  41. package/dist/cli/handlers/db/index.js +17 -1
  42. package/dist/cli/handlers/db/migration.js +245 -0
  43. package/dist/cli/handlers/db/quota.js +68 -0
  44. package/dist/cli/handlers/db/recovery.js +387 -0
  45. package/dist/cli/handlers/db/schema.js +35 -36
  46. package/dist/cli/handlers/db/sql.js +70 -71
  47. package/dist/cli/handlers/deploy/deploy.js +84 -0
  48. package/dist/cli/handlers/deploy/error-log.js +60 -0
  49. package/dist/cli/handlers/deploy/format.js +39 -0
  50. package/dist/cli/handlers/deploy/get.js +71 -0
  51. package/dist/cli/handlers/deploy/helpers.js +41 -0
  52. package/dist/cli/handlers/deploy/history.js +70 -0
  53. package/dist/cli/handlers/deploy/index.js +14 -0
  54. package/dist/cli/handlers/deploy/polling.js +162 -0
  55. package/dist/cli/handlers/file/cp.js +31 -32
  56. package/dist/cli/handlers/file/index.js +3 -1
  57. package/dist/cli/handlers/file/ls.js +6 -7
  58. package/dist/cli/handlers/file/quota.js +66 -0
  59. package/dist/cli/handlers/file/rm.js +33 -32
  60. package/dist/cli/handlers/file/sign.js +4 -5
  61. package/dist/cli/handlers/file/stat.js +11 -11
  62. package/dist/cli/handlers/observability/analytics.js +212 -0
  63. package/dist/cli/handlers/observability/helpers.js +66 -0
  64. package/dist/cli/handlers/observability/index.js +12 -0
  65. package/dist/cli/handlers/observability/log.js +94 -0
  66. package/dist/cli/handlers/observability/metric.js +208 -0
  67. package/dist/cli/handlers/observability/trace.js +102 -0
  68. package/dist/cli/handlers/plugin/plugin-local.js +53 -53
  69. package/dist/cli/handlers/plugin/plugin.js +15 -15
  70. package/dist/cli/help.js +16 -16
  71. package/dist/main.js +13 -9
  72. package/dist/utils/args.js +8 -0
  73. package/dist/utils/colors.js +2 -2
  74. package/dist/utils/config.js +2 -2
  75. package/dist/utils/devops-error.js +28 -0
  76. package/dist/utils/error.js +2 -2
  77. package/dist/utils/git.js +29 -0
  78. package/dist/utils/http.js +119 -1
  79. package/dist/utils/index.js +15 -1
  80. package/dist/utils/output.js +373 -20
  81. package/dist/utils/poll.js +35 -0
  82. package/dist/utils/render.js +27 -27
  83. package/dist/utils/spinner.js +46 -0
  84. package/dist/utils/time.js +208 -0
  85. package/package.json +7 -5
@@ -20,9 +20,9 @@ function traceHttp(method, url, start, response, err) {
20
20
  try {
21
21
  const cost = Date.now() - start;
22
22
  const status = response?.status ?? 0;
23
- const logid = response?.headers?.get?.("x-tt-logid") ?? "-";
23
+ const logid = response?.headers?.get?.('x-tt-logid') ?? '-';
24
24
  if (err !== undefined) {
25
- const errMsg = err instanceof Error ? err.message : typeof err === "string" ? err : JSON.stringify(err);
25
+ const errMsg = err instanceof Error ? err.message : typeof err === 'string' ? err : JSON.stringify(err);
26
26
  (0, logger_1.debug)(`http ${method} ${url} ${String(status)} cost=${String(cost)}ms x-tt-logid=${logid} err=${errMsg}`);
27
27
  return;
28
28
  }
@@ -51,7 +51,7 @@ async function getDefaultBucketId(appId) {
51
51
  ensureSuccess(body);
52
52
  const bucketId = body.data?.app_runtime_extra?.bucket?.default_bucket_id;
53
53
  if (!bucketId) {
54
- throw new error_1.AppError("BUCKET_NOT_FOUND", `No default bucket for app '${appId}'`);
54
+ throw new error_1.AppError('BUCKET_NOT_FOUND', `No default bucket for app '${appId}'`);
55
55
  }
56
56
  bucketCache.set(appId, bucketId);
57
57
  return bucketId;
@@ -81,31 +81,53 @@ function resetBucketCache() {
81
81
  */
82
82
  const BIZ_ERR_MAP = new Map(Object.entries({
83
83
  k_img_ec_000034: {
84
- code: "FILE_NOT_FOUND",
85
- message: "File does not exist",
86
- hint: "Run `miaoda file ls` to see available files.",
84
+ code: 'FILE_NOT_FOUND',
85
+ message: 'File does not exist',
86
+ hint: 'Run `miaoda file ls` to see available files.',
87
87
  },
88
88
  k_img_ec_000035: {
89
- code: "FILE_ALREADY_EXISTS",
90
- message: "A file at this path already exists",
91
- hint: "Rename the target or delete the existing file first (`miaoda file rm`).",
89
+ code: 'FILE_ALREADY_EXISTS',
90
+ message: 'A file at this path already exists',
91
+ hint: 'Rename the target or delete the existing file first (`miaoda file rm`).',
92
+ },
93
+ // k_ec_000040:file-storage 上游引擎层连不上下游服务(依赖抖动 / 远端 RPC 失败)。
94
+ // 文案不向用户暴露内部 code,统一成 INTERNAL_API_ERROR + 重试引导。
95
+ k_ec_000040: {
96
+ code: 'INTERNAL_API_ERROR',
97
+ message: 'Service temporarily unavailable',
98
+ hint: 'Please retry the command. If it keeps failing, share the x-tt-logid (via --verbose) with the on-call team.',
92
99
  },
93
100
  }));
101
+ // k_ec_* 命名空间是 file-storage 引擎层通用错误(基础设施 / 上游 RPC),不是
102
+ // 用户输入问题。无显式条目时统一兜底成 INTERNAL_API_ERROR + 重试 hint,避免
103
+ // 暴露内部 code 给最终用户。
104
+ function isEngineCommonError(code) {
105
+ return /^k_ec_\d+$/.test(code);
106
+ }
94
107
  function ensureSuccess(body) {
95
108
  // 后端 envelope 字段历史遗留多种命名:
96
109
  // - ErrorCode / error_code: 部分接口
97
110
  // - status_code: delete / sign / head / preUpload 等新接口
98
- const code = body.ErrorCode ?? body.error_code ?? body.status_code ?? "0";
99
- if (code === "0" || code === "")
111
+ const code = body.ErrorCode ?? body.error_code ?? body.status_code ?? '0';
112
+ if (code === '0' || code === '')
100
113
  return;
101
114
  // 错误 message 字段同样散:ErrorMessage / error_message / error_msg / Message
102
- const backendMsg = body.ErrorMessage ?? body.error_message ?? body.error_msg ?? body.Message ?? "unknown error";
115
+ const backendMsg = body.ErrorMessage ?? body.error_message ?? body.error_msg ?? body.Message ?? 'unknown error';
103
116
  const mapped = BIZ_ERR_MAP.get(code);
104
117
  if (mapped) {
105
118
  throw new error_1.AppError(mapped.code, mapped.message ?? backendMsg, {
106
119
  next_actions: mapped.hint ? [mapped.hint] : undefined,
107
120
  });
108
121
  }
122
+ // k_ec_* 引擎层错误统一兜底:用户视角是"服务暂时不可用",重试即可,
123
+ // 不要把 `File API error [k_ec_000xxx]: <内部翻译>` 这种半成品文案抛给用户。
124
+ if (isEngineCommonError(code)) {
125
+ throw new error_1.AppError('INTERNAL_API_ERROR', 'Service temporarily unavailable', {
126
+ next_actions: [
127
+ `Please retry the command. If it keeps failing, share the x-tt-logid (via --verbose) with the on-call team. (upstream code: ${code})`,
128
+ ],
129
+ });
130
+ }
109
131
  throw new error_1.AppError(`FILE_API_${code}`, `File API error [${code}]: ${backendMsg}`);
110
132
  }
111
133
  /** 从 HttpError 的 response 里尝试读 body,用于拿后端返的业务 ErrorCode。 */
@@ -128,22 +150,40 @@ async function mapHttpError(err, opts) {
128
150
  const body = await extractBody(err.response);
129
151
  // 1. 先看后端业务 ErrorCode(优先级最高)
130
152
  if (body) {
131
- const code = body.ErrorCode ?? body.error_code ?? "";
132
- if (code && code !== "0") {
153
+ const code = body.ErrorCode ?? body.error_code ?? '';
154
+ if (code && code !== '0') {
155
+ const mapped = BIZ_ERR_MAP.get(code);
156
+ if (mapped) {
157
+ const msg = body.ErrorMessage ??
158
+ body.error_message ??
159
+ body.Message ??
160
+ mapped.message ??
161
+ err.message;
162
+ throw new error_1.AppError(mapped.code, mapped.message ?? msg, {
163
+ next_actions: mapped.hint ? [mapped.hint] : undefined,
164
+ });
165
+ }
166
+ if (isEngineCommonError(code)) {
167
+ throw new error_1.AppError('INTERNAL_API_ERROR', 'Service temporarily unavailable', {
168
+ next_actions: [
169
+ `Please retry the command. If it keeps failing, share the x-tt-logid (via --verbose) with the on-call team. (upstream code: ${code})`,
170
+ ],
171
+ });
172
+ }
133
173
  const msg = body.ErrorMessage ?? body.error_message ?? body.Message ?? err.message;
134
174
  throw new error_1.AppError(`FILE_API_${code}`, `File API error [${code}]: ${msg}`);
135
175
  }
136
176
  }
137
177
  // 2. 404 常见情况 —— 路径不存在,映射到业务语义
138
178
  if (status === 404 && opts.notFoundCode) {
139
- throw new error_1.AppError(opts.notFoundCode, opts.notFoundMessage ?? "resource not found", {
179
+ throw new error_1.AppError(opts.notFoundCode, opts.notFoundMessage ?? 'resource not found', {
140
180
  next_actions: opts.notFoundHint ? [opts.notFoundHint] : undefined,
141
181
  });
142
182
  }
143
183
  // 3. 兜底:保留原始 status 的 HttpError(给上层看到真实状态码)
144
- const ctx = opts.errorContext ?? "HTTP request failed";
145
- const statusText = err.response?.statusText ?? "";
146
- throw new error_1.HttpError(status, err.config.url ?? "", `${ctx}: ${String(status)} ${statusText}`.trim());
184
+ const ctx = opts.errorContext ?? 'HTTP request failed';
185
+ const statusText = err.response?.statusText ?? '';
186
+ throw new error_1.HttpError(status, err.config.url ?? '', `${ctx}: ${String(status)} ${statusText}`.trim());
147
187
  }
148
188
  throw err;
149
189
  }
@@ -156,11 +196,11 @@ async function doGet(url, opts = {}, client = (0, http_1.getHttpClient)()) {
156
196
  const start = Date.now();
157
197
  try {
158
198
  const response = await client.get(url);
159
- traceHttp("GET", url, start, response);
199
+ traceHttp('GET', url, start, response);
160
200
  return (await response.json());
161
201
  }
162
202
  catch (err) {
163
- traceHttp("GET", url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
203
+ traceHttp('GET', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
164
204
  await mapHttpError(err, opts);
165
205
  throw err; // 不可达,mapHttpError 必定 throw
166
206
  }
@@ -170,11 +210,11 @@ async function doPost(url, body, opts = {}, client = (0, http_1.getHttpClient)()
170
210
  const start = Date.now();
171
211
  try {
172
212
  const response = await client.post(url, body);
173
- traceHttp("POST", url, start, response);
213
+ traceHttp('POST', url, start, response);
174
214
  return (await response.json());
175
215
  }
176
216
  catch (err) {
177
- traceHttp("POST", url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
217
+ traceHttp('POST', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
178
218
  await mapHttpError(err, opts);
179
219
  throw err;
180
220
  }
@@ -41,9 +41,9 @@ const BACKEND_KEY_PATTERN = /^\d{16,}(?:\.[a-zA-Z0-9]{1,10}){0,2}$/;
41
41
  function looksLikePath(input) {
42
42
  if (!input)
43
43
  return false;
44
- if (input.startsWith("/"))
44
+ if (input.startsWith('/'))
45
45
  return true;
46
- if (input.includes("/"))
46
+ if (input.includes('/'))
47
47
  return true;
48
48
  return BACKEND_KEY_PATTERN.test(input);
49
49
  }
@@ -52,5 +52,5 @@ function looksLikePath(input) {
52
52
  * 便于从 auto-detected 的 "abc123...xyz.txt" 回到统一的 `/abc123...xyz.txt`。
53
53
  */
54
54
  function toAbsolutePath(input) {
55
- return input.startsWith("/") ? input : `/${input}`;
55
+ return input.startsWith('/') ? input : `/${input}`;
56
56
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.toAbsolutePath = exports.looksLikePath = exports.resetBucketCache = exports.getDefaultBucketId = exports.parseTimeFilterMs = exports.resolveInputs = exports.deleteFiles = exports.downloadFile = exports.signDownload = exports.uploadFile = exports.statFile = exports.listFiles = void 0;
3
+ exports.toAbsolutePath = exports.looksLikePath = exports.resetBucketCache = exports.getDefaultBucketId = exports.getStorageQuota = exports.parseTimeFilterMs = exports.resolveInputs = exports.deleteFiles = exports.downloadFile = exports.signDownload = exports.uploadFile = exports.statFile = exports.listFiles = void 0;
4
4
  var api_1 = require("./api");
5
5
  Object.defineProperty(exports, "listFiles", { enumerable: true, get: function () { return api_1.listFiles; } });
6
6
  Object.defineProperty(exports, "statFile", { enumerable: true, get: function () { return api_1.statFile; } });
@@ -10,6 +10,7 @@ Object.defineProperty(exports, "downloadFile", { enumerable: true, get: function
10
10
  Object.defineProperty(exports, "deleteFiles", { enumerable: true, get: function () { return api_1.deleteFiles; } });
11
11
  Object.defineProperty(exports, "resolveInputs", { enumerable: true, get: function () { return api_1.resolveInputs; } });
12
12
  Object.defineProperty(exports, "parseTimeFilterMs", { enumerable: true, get: function () { return api_1.parseTimeFilterMs; } });
13
+ Object.defineProperty(exports, "getStorageQuota", { enumerable: true, get: function () { return api_1.getStorageQuota; } });
13
14
  var client_1 = require("./client");
14
15
  Object.defineProperty(exports, "getDefaultBucketId", { enumerable: true, get: function () { return client_1.getDefaultBucketId; } });
15
16
  Object.defineProperty(exports, "resetBucketCache", { enumerable: true, get: function () { return client_1.resetBucketCache; } });
@@ -3,12 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseAttachment = parseAttachment;
4
4
  exports.parseHead = parseHead;
5
5
  /** 安全读取字符串字段(空字符串回退为默认值) */
6
- function str(value, fallback = "") {
7
- return typeof value === "string" && value.length > 0 ? value : fallback;
6
+ function str(value, fallback = '') {
7
+ return typeof value === 'string' && value.length > 0 ? value : fallback;
8
8
  }
9
9
  /** 安全读取数字字段(非正值回退到 0) */
10
10
  function int(value) {
11
- if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
11
+ if (typeof value === 'number' && Number.isFinite(value) && value >= 0) {
12
12
  return Math.trunc(value);
13
13
  }
14
14
  return 0;
@@ -26,7 +26,7 @@ function readSize(meta) {
26
26
  function toDisplayPath(p) {
27
27
  if (!p)
28
28
  return p;
29
- return p.startsWith("/") ? p : `/${p}`;
29
+ return p.startsWith('/') ? p : `/${p}`;
30
30
  }
31
31
  /** 将后端 attachment 结构映射为 CLI FileInfo(用于 ls) */
32
32
  function parseAttachment(att) {
@@ -41,8 +41,9 @@ function parseAttachment(att) {
41
41
  const downloadUrl = str(att.downloadURL);
42
42
  if (downloadUrl)
43
43
  info.download_url = downloadUrl;
44
- // uploaded_by createdBy.name 映射(后端返 {userID, name, email, ...},空代表匿名)
45
- const uploader = str(att.createdBy?.name);
44
+ // uploaded_by 输出 {id, name} 对象:后端 createdBy: {userID, name, email, ...}
45
+ // 任一非空都建对象;JSON 用对象、pretty 渲染只取 name
46
+ const uploader = toUploaderRef(att.createdBy);
46
47
  if (uploader)
47
48
  info.uploaded_by = uploader;
48
49
  return info;
@@ -61,8 +62,18 @@ function parseHead(data, filePath) {
61
62
  const downloadUrl = str(outer.downloadURL);
62
63
  if (downloadUrl)
63
64
  info.download_url = downloadUrl;
64
- const uploader = str(outer.createdBy?.name);
65
+ const uploader = toUploaderRef(outer.createdBy);
65
66
  if (uploader)
66
67
  info.uploaded_by = uploader;
67
68
  return info;
68
69
  }
70
+ /** 把后端 UserRef 归一成 CLI 暴露的 {id, name};id / name 全空时返 undefined 略过字段。 */
71
+ function toUploaderRef(user) {
72
+ if (!user)
73
+ return undefined;
74
+ const id = str(user.userID);
75
+ const name = str(user.name);
76
+ if (id === '' && name === '')
77
+ return undefined;
78
+ return { id, name };
79
+ }
package/dist/api/index.js CHANGED
@@ -33,10 +33,16 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.db = exports.file = exports.plugin = void 0;
36
+ exports.deploy = exports.app = exports.observability = exports.db = exports.file = exports.plugin = void 0;
37
37
  const _plugin = __importStar(require("../api/plugin/index"));
38
38
  const _file = __importStar(require("../api/file/index"));
39
39
  const _db = __importStar(require("../api/db/index"));
40
+ const _observability = __importStar(require("../api/observability/index"));
41
+ const _app = __importStar(require("../api/app/index"));
42
+ const _deploy = __importStar(require("../api/deploy/index"));
40
43
  exports.plugin = { ..._plugin };
41
44
  exports.file = { ..._file };
42
45
  exports.db = { ..._db };
46
+ exports.observability = { ..._observability };
47
+ exports.app = { ..._app };
48
+ exports.deploy = { ..._deploy };
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.searchLogs = searchLogs;
4
+ exports.searchTraces = searchTraces;
5
+ exports.getTraces = getTraces;
6
+ exports.queryMetricsData = queryMetricsData;
7
+ exports.queryAnalyticsData = queryAnalyticsData;
8
+ const http_1 = require("../../utils/http");
9
+ const DEFAULT_ERR_CODE = 'INTERNAL_OB_ERROR';
10
+ // ── 日志 ──
11
+ async function searchLogs(req) {
12
+ const url = `/v1/observability/app/${encodeURIComponent(req.appID)}/logs/search`;
13
+ return (0, http_1.postInnerApi)(url, req, {
14
+ errPrefix: 'Failed to search logs',
15
+ defaultErrCode: DEFAULT_ERR_CODE,
16
+ });
17
+ }
18
+ // ── 链路 ──
19
+ async function searchTraces(req) {
20
+ const url = `/v1/observability/app/${encodeURIComponent(req.appID)}/traces/search`;
21
+ return (0, http_1.postInnerApi)(url, req, {
22
+ errPrefix: 'Failed to search traces',
23
+ defaultErrCode: DEFAULT_ERR_CODE,
24
+ });
25
+ }
26
+ async function getTraces(req) {
27
+ const url = `/v1/observability/app/${encodeURIComponent(req.appID)}/traces/${encodeURIComponent(req.traceID)}`;
28
+ return (0, http_1.postInnerApi)(url, req, {
29
+ errPrefix: 'Failed to get trace',
30
+ defaultErrCode: DEFAULT_ERR_CODE,
31
+ });
32
+ }
33
+ // ── 监控指标 ──
34
+ async function queryMetricsData(req) {
35
+ const url = `/v1/observability/app/${encodeURIComponent(req.appID)}/metrics/data/query`;
36
+ return (0, http_1.postInnerApi)(url, req, {
37
+ errPrefix: 'Failed to query metrics',
38
+ defaultErrCode: DEFAULT_ERR_CODE,
39
+ });
40
+ }
41
+ // ── 运营指标 ──
42
+ //
43
+ // 走 BAM v1.0.122 起的批量端点 CLIBatchQueryAnalyticsData:
44
+ // - 路径 /analytics/data/batch_query(旧版 /analytics/data/query 已废弃)
45
+ // - 支持 metricTypes 数组,单次拉多个指标
46
+ async function queryAnalyticsData(req) {
47
+ const url = `/v1/observability/app/${encodeURIComponent(req.appID)}/analytics/data/batch_query`;
48
+ return (0, http_1.postInnerApi)(url, req, {
49
+ errPrefix: 'Failed to query analytics',
50
+ defaultErrCode: DEFAULT_ERR_CODE,
51
+ });
52
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StatusCode = exports.SpanKind = exports.WordOperator = exports.spanSchema = exports.logItemSchema = exports.queryAnalyticsData = exports.queryMetricsData = exports.getTraces = exports.searchTraces = exports.searchLogs = void 0;
4
+ var api_1 = require("./api");
5
+ Object.defineProperty(exports, "searchLogs", { enumerable: true, get: function () { return api_1.searchLogs; } });
6
+ Object.defineProperty(exports, "searchTraces", { enumerable: true, get: function () { return api_1.searchTraces; } });
7
+ Object.defineProperty(exports, "getTraces", { enumerable: true, get: function () { return api_1.getTraces; } });
8
+ Object.defineProperty(exports, "queryMetricsData", { enumerable: true, get: function () { return api_1.queryMetricsData; } });
9
+ Object.defineProperty(exports, "queryAnalyticsData", { enumerable: true, get: function () { return api_1.queryAnalyticsData; } });
10
+ var schemas_1 = require("./schemas");
11
+ Object.defineProperty(exports, "logItemSchema", { enumerable: true, get: function () { return schemas_1.logItemSchema; } });
12
+ Object.defineProperty(exports, "spanSchema", { enumerable: true, get: function () { return schemas_1.spanSchema; } });
13
+ var types_1 = require("./types");
14
+ Object.defineProperty(exports, "WordOperator", { enumerable: true, get: function () { return types_1.WordOperator; } });
15
+ Object.defineProperty(exports, "SpanKind", { enumerable: true, get: function () { return types_1.SpanKind; } });
16
+ Object.defineProperty(exports, "StatusCode", { enumerable: true, get: function () { return types_1.StatusCode; } });
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.spanSchema = exports.logItemSchema = void 0;
4
+ const output_1 = require("../../utils/output");
5
+ /** LogItem 渲染契约(log search) */
6
+ exports.logItemSchema = {
7
+ columns: [
8
+ { key: 'timestampNs', label: 'time', format: output_1.fmt.ns('yyyy-MM-dd HH:mm:ss.SSS') },
9
+ {
10
+ key: 'module',
11
+ derive: (row) => {
12
+ return row.attributes?.module;
13
+ },
14
+ },
15
+ {
16
+ key: 'user-id',
17
+ derive: (row) => {
18
+ return row.attributes?.user_id;
19
+ },
20
+ },
21
+ { key: 'severityText', label: 'severity-text' },
22
+ {
23
+ key: 'duration',
24
+ format: output_1.fmt.durationMs(),
25
+ derive: (row) => {
26
+ return row.attributes?.duration_ms;
27
+ },
28
+ },
29
+ { key: 'traceID', label: 'trace-id' },
30
+ { key: 'id', label: 'log-id' },
31
+ { key: 'body' },
32
+ ],
33
+ strict: true,
34
+ };
35
+ /** Span 渲染契约(trace list / trace get 复用)。
36
+ * duration 是 client-derived(BAM 只给 start/end,没有原生 durationNs 字段)。 */
37
+ exports.spanSchema = {
38
+ columns: [
39
+ { key: 'startTimeUnixNano', label: 'start-time', format: output_1.fmt.ns('yyyy-MM-dd HH:mm:ss.SSS') },
40
+ { key: 'name', label: 'root-span' },
41
+ {
42
+ key: 'user-id',
43
+ derive: (row) => {
44
+ return row.attributes?.user_id;
45
+ },
46
+ },
47
+ {
48
+ key: 'duration',
49
+ label: 'duration',
50
+ format: output_1.fmt.durationMs(),
51
+ derive: (row) => {
52
+ return row.attributes?.duration_ms;
53
+ },
54
+ },
55
+ { key: 'traceID', label: 'trace-id' },
56
+ ],
57
+ strict: true,
58
+ };
59
+ // metric / analytics 都改用 BAM v1.0.123 起的合并响应(points: {timestamp, values}),
60
+ // pretty 渲染走 handler 内 pivot 后的临时 schema;不再导出固定 schema。
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ // ── 通用结构 ──
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.StatusCode = exports.SpanKind = exports.WordOperator = void 0;
5
+ /** 模糊搜索词运算符(对应后端 WordOperator) */
6
+ var WordOperator;
7
+ (function (WordOperator) {
8
+ WordOperator[WordOperator["AND"] = 0] = "AND";
9
+ WordOperator[WordOperator["OR"] = 1] = "OR";
10
+ })(WordOperator || (exports.WordOperator = WordOperator = {}));
11
+ /** OpenTelemetry SpanKind(BAM 透传) */
12
+ var SpanKind;
13
+ (function (SpanKind) {
14
+ SpanKind[SpanKind["UNSPECIFIED"] = 0] = "UNSPECIFIED";
15
+ SpanKind[SpanKind["INTERNAL"] = 1] = "INTERNAL";
16
+ SpanKind[SpanKind["SERVER"] = 2] = "SERVER";
17
+ SpanKind[SpanKind["CLIENT"] = 3] = "CLIENT";
18
+ SpanKind[SpanKind["PRODUCER"] = 4] = "PRODUCER";
19
+ SpanKind[SpanKind["CONSUMER"] = 5] = "CONSUMER";
20
+ })(SpanKind || (exports.SpanKind = SpanKind = {}));
21
+ /** Span 状态码(BAM 透传) */
22
+ var StatusCode;
23
+ (function (StatusCode) {
24
+ StatusCode[StatusCode["UNSET"] = 0] = "UNSET";
25
+ StatusCode[StatusCode["OK"] = 1] = "OK";
26
+ StatusCode[StatusCode["ERROR"] = 2] = "ERROR";
27
+ })(StatusCode || (exports.StatusCode = StatusCode = {}));
@@ -23,23 +23,23 @@ const node_path_1 = __importDefault(require("node:path"));
23
23
  // ── Plugin Version API ──
24
24
  async function getPluginVersions(keys, latestOnly = true) {
25
25
  const client = (0, http_1.getRuntimeHttpClient)();
26
- const response = await client.post(`/api/v1/studio/innerapi/plugins/-/versions/batch_get?keys=${keys.join(",")}&latest_only=${String(latestOnly)}`);
26
+ const response = await client.post(`/api/v1/studio/innerapi/plugins/-/versions/batch_get?keys=${keys.join(',')}&latest_only=${String(latestOnly)}`);
27
27
  if (!response.ok) {
28
28
  throw new error_1.HttpError(response.status, response.url, `Failed to get plugin versions: ${String(response.status)} ${response.statusText}`);
29
29
  }
30
30
  const result = (await response.json());
31
- if (result.status_code !== "0") {
32
- throw new error_1.AppError("INTERNAL_API_ERROR", `API error: ${result.message ?? "unknown"}`);
31
+ if (result.status_code !== '0') {
32
+ throw new error_1.AppError('INTERNAL_API_ERROR', `API error: ${result.message ?? 'unknown'}`);
33
33
  }
34
34
  return result.data.pluginVersions;
35
35
  }
36
36
  async function getPluginVersion(pluginKey, requestedVersion) {
37
- const isLatest = requestedVersion === "latest";
37
+ const isLatest = requestedVersion === 'latest';
38
38
  const versions = await getPluginVersions([pluginKey], isLatest);
39
39
  const pluginVersions = versions[pluginKey];
40
40
  if (!pluginVersions || pluginVersions.length === 0) {
41
- throw new error_1.AppError("PLUGIN_NOT_FOUND", `Plugin not found: ${pluginKey}`, {
42
- next_actions: ["检查包名拼写,或确认该插件已在插件市场发布"],
41
+ throw new error_1.AppError('PLUGIN_NOT_FOUND', `Plugin not found: ${pluginKey}`, {
42
+ next_actions: ['检查包名拼写,或确认该插件已在插件市场发布'],
43
43
  });
44
44
  }
45
45
  if (isLatest) {
@@ -47,7 +47,7 @@ async function getPluginVersion(pluginKey, requestedVersion) {
47
47
  }
48
48
  const targetVersion = pluginVersions.find((v) => v.version === requestedVersion);
49
49
  if (!targetVersion) {
50
- throw new error_1.AppError("VERSION_NOT_FOUND", `Version ${requestedVersion} not found for plugin ${pluginKey}`, { next_actions: [`可用版本:${pluginVersions.map((v) => v.version).join(", ")}`] });
50
+ throw new error_1.AppError('VERSION_NOT_FOUND', `Version ${requestedVersion} not found for plugin ${pluginKey}`, { next_actions: [`可用版本:${pluginVersions.map((v) => v.version).join(', ')}`] });
51
51
  }
52
52
  return targetVersion;
53
53
  }
@@ -55,8 +55,8 @@ async function getPluginVersion(pluginKey, requestedVersion) {
55
55
  function parsePluginKey(key) {
56
56
  const match = /^(@[^/]+)\/(.+)$/.exec(key);
57
57
  if (!match) {
58
- throw new error_1.AppError("INVALID_PLUGIN_KEY", `Invalid plugin key format: ${key}`, {
59
- next_actions: ["插件 key 必须形如 @scope/name"],
58
+ throw new error_1.AppError('INVALID_PLUGIN_KEY', `Invalid plugin key format: ${key}`, {
59
+ next_actions: ['插件 key 必须形如 @scope/name'],
60
60
  });
61
61
  }
62
62
  return { scope: match[1], name: match[2] };
@@ -91,15 +91,15 @@ async function withRetry(operation, description, maxRetries = MAX_RETRIES) {
91
91
  catch (error) {
92
92
  lastError = error instanceof Error ? error : new Error(String(error));
93
93
  if (attempt < maxRetries) {
94
- (0, logger_1.log)("plugin", `${description} failed, retrying (${String(attempt + 1)}/${String(maxRetries)})...`);
94
+ (0, logger_1.log)('plugin', `${description} failed, retrying (${String(attempt + 1)}/${String(maxRetries)})...`);
95
95
  }
96
96
  }
97
97
  }
98
98
  throw (lastError ??
99
- new error_1.AppError("INTERNAL_RETRY_EXHAUSTED", `${description} failed after ${String(maxRetries)} retries`, { retryable: true, next_actions: ["检查网络后重试,--verbose 可查看重试日志"] }));
99
+ new error_1.AppError('INTERNAL_RETRY_EXHAUSTED', `${description} failed after ${String(maxRetries)} retries`, { retryable: true, next_actions: ['检查网络后重试,--verbose 可查看重试日志'] }));
100
100
  }
101
101
  /** 插件缓存目录 */
102
- const PLUGIN_CACHE_DIR = "node_modules/.cache/miaoda-cli/plugins";
102
+ const PLUGIN_CACHE_DIR = 'node_modules/.cache/miaoda-cli/plugins';
103
103
  function getPluginCacheDir() {
104
104
  return node_path_1.default.join(process.cwd(), PLUGIN_CACHE_DIR);
105
105
  }
@@ -111,18 +111,18 @@ function ensureCacheDir() {
111
111
  }
112
112
  function getTempFilePath(pluginKey, version) {
113
113
  ensureCacheDir();
114
- const safeKey = pluginKey.replace(/[/@]/g, "_");
114
+ const safeKey = pluginKey.replace(/[/@]/g, '_');
115
115
  const filename = `${safeKey}@${version}.tgz`;
116
116
  return node_path_1.default.join(getPluginCacheDir(), filename);
117
117
  }
118
118
  async function downloadPlugin(pluginKey, requestedVersion) {
119
119
  const pluginInfo = await getPluginVersion(pluginKey, requestedVersion);
120
120
  let tgzBuffer;
121
- if (pluginInfo.downloadApproach === "inner") {
122
- tgzBuffer = await withRetry(() => downloadFromInner(pluginKey, pluginInfo.version), "Download");
121
+ if (pluginInfo.downloadApproach === 'inner') {
122
+ tgzBuffer = await withRetry(() => downloadFromInner(pluginKey, pluginInfo.version), 'Download');
123
123
  }
124
124
  else {
125
- tgzBuffer = await withRetry(() => downloadFromPublic(pluginInfo.downloadURL), "Download");
125
+ tgzBuffer = await withRetry(() => downloadFromPublic(pluginInfo.downloadURL), 'Download');
126
126
  }
127
127
  const tgzPath = getTempFilePath(pluginKey, pluginInfo.version);
128
128
  node_fs_1.default.writeFileSync(tgzPath, tgzBuffer);
@@ -135,7 +135,7 @@ async function downloadPlugin(pluginKey, requestedVersion) {
135
135
  // ── Cache ──
136
136
  function getCachePath(pluginKey, version) {
137
137
  ensureCacheDir();
138
- const safeKey = pluginKey.replace(/[/@]/g, "_");
138
+ const safeKey = pluginKey.replace(/[/@]/g, '_');
139
139
  const filename = `${safeKey}@${version}.tgz`;
140
140
  return node_path_1.default.join(getPluginCacheDir(), filename);
141
141
  }
@@ -151,13 +151,13 @@ function listCachedPlugins() {
151
151
  const files = node_fs_1.default.readdirSync(cacheDir);
152
152
  const result = [];
153
153
  for (const file of files) {
154
- if (!file.endsWith(".tgz"))
154
+ if (!file.endsWith('.tgz'))
155
155
  continue;
156
156
  const match = /^(.+)@(.+)\.tgz$/.exec(file);
157
157
  if (!match)
158
158
  continue;
159
159
  const [, rawName, version] = match;
160
- const name = rawName.replace(/^_/, "@").replace(/_/, "/");
160
+ const name = rawName.replace(/^_/, '@').replace(/_/, '/');
161
161
  const filePath = node_path_1.default.join(cacheDir, file);
162
162
  const stat = node_fs_1.default.statSync(filePath);
163
163
  result.push({ name, version, filePath, size: stat.size, mtime: stat.mtime });
@@ -172,7 +172,7 @@ function cleanAllCache() {
172
172
  const files = node_fs_1.default.readdirSync(cacheDir);
173
173
  let count = 0;
174
174
  for (const file of files) {
175
- if (file.endsWith(".tgz")) {
175
+ if (file.endsWith('.tgz')) {
176
176
  node_fs_1.default.unlinkSync(node_path_1.default.join(cacheDir, file));
177
177
  count++;
178
178
  }
@@ -184,7 +184,7 @@ function cleanPluginCache(pluginKey, version) {
184
184
  if (!node_fs_1.default.existsSync(cacheDir)) {
185
185
  return 0;
186
186
  }
187
- const safeKey = pluginKey.replace(/[/@]/g, "_");
187
+ const safeKey = pluginKey.replace(/[/@]/g, '_');
188
188
  const files = node_fs_1.default.readdirSync(cacheDir);
189
189
  let count = 0;
190
190
  for (const file of files) {
@@ -195,7 +195,7 @@ function cleanPluginCache(pluginKey, version) {
195
195
  }
196
196
  }
197
197
  else {
198
- if (file.startsWith(`${safeKey}@`) && file.endsWith(".tgz")) {
198
+ if (file.startsWith(`${safeKey}@`) && file.endsWith('.tgz')) {
199
199
  node_fs_1.default.unlinkSync(node_path_1.default.join(cacheDir, file));
200
200
  count++;
201
201
  }
@@ -209,29 +209,29 @@ async function reportEvents(events) {
209
209
  return true;
210
210
  try {
211
211
  const client = (0, http_1.getRuntimeHttpClient)();
212
- const response = await client.post("/api/v1/studio/innerapi/resource_events", { events });
212
+ const response = await client.post('/api/v1/studio/innerapi/resource_events', { events });
213
213
  if (!response.ok) {
214
- (0, logger_1.log)("telemetry", `Failed to report events: ${String(response.status)} ${response.statusText}`);
214
+ (0, logger_1.log)('telemetry', `Failed to report events: ${String(response.status)} ${response.statusText}`);
215
215
  return false;
216
216
  }
217
217
  const result = (await response.json());
218
- if (result.status_code !== "0") {
219
- (0, logger_1.log)("telemetry", `API error: ${result.message ?? "unknown"}`);
218
+ if (result.status_code !== '0') {
219
+ (0, logger_1.log)('telemetry', `API error: ${result.message ?? 'unknown'}`);
220
220
  return false;
221
221
  }
222
222
  return true;
223
223
  }
224
224
  catch (error) {
225
- (0, logger_1.log)("telemetry", `Failed to report events: ${error instanceof Error ? error.message : String(error)}`);
225
+ (0, logger_1.log)('telemetry', `Failed to report events: ${error instanceof Error ? error.message : String(error)}`);
226
226
  return false;
227
227
  }
228
228
  }
229
229
  async function reportInstallEvent(pluginKey, version) {
230
230
  await reportEvents([
231
231
  {
232
- resourceType: "plugin",
232
+ resourceType: 'plugin',
233
233
  resourceKey: pluginKey,
234
- eventType: "install",
234
+ eventType: 'install',
235
235
  details: { version },
236
236
  },
237
237
  ]);
@@ -239,9 +239,9 @@ async function reportInstallEvent(pluginKey, version) {
239
239
  async function reportCreateInstanceEvent(pluginKey, version) {
240
240
  await reportEvents([
241
241
  {
242
- resourceType: "plugin",
242
+ resourceType: 'plugin',
243
243
  resourceKey: pluginKey,
244
- eventType: "create_instance",
244
+ eventType: 'create_instance',
245
245
  details: { version },
246
246
  },
247
247
  ]);