@lark-apaas/miaoda-cli 0.1.3-alpha.70f9b2d → 0.1.3-alpha.848d934

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.
@@ -436,7 +436,9 @@ async function listAuditLog(opts) {
436
436
  }
437
437
  const client = (0, http_1.getHttpClient)();
438
438
  const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/audit/log', {
439
- tables: opts.tables.join(','),
439
+ // IDL `Tables list<string>` 走重复 query key(?tables=A&tables=B)—— join(',')
440
+ // 会让 Hertz/Kitex 网关绑成 ["A,B"] 单元素切片,命中单表错误分支报错文案错乱。
441
+ tables: opts.tables,
440
442
  since: opts.since,
441
443
  until: opts.until,
442
444
  limit: opts.limit !== undefined ? String(opts.limit) : undefined,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.SQLSTATE_MAP = void 0;
3
+ exports.SQLSTATE_MAP = exports.ENV_CTX_TYPO = void 0;
4
4
  exports.traceHttp = traceHttp;
5
5
  exports.ensureInnerSuccess = ensureInnerSuccess;
6
6
  exports.mapDataloomBizError = mapDataloomBizError;
@@ -71,7 +71,8 @@ function ensureInnerSuccess(body) {
71
71
  *
72
72
  * 优先级:
73
73
  * 1. k_dl_1300002 + SQLSTATE 透传 → SQLSTATE_MAP
74
- * 2. k_dl_1600000 + "Invalid DB Branch" → MULTI_ENV_NOT_INITIALIZED
74
+ * 2. k_dl_1600000 + "Invalid DB Branch" → UNKNOWN_ENV_VALUE 占位(mapDbHttpError
75
+ * 会用用户实际 --env 值通过 decorateEnvError 重写)
75
76
  * 3. BIZ_ERR_MAP 命中 → 语义 code(可能带 hint)
76
77
  * 4. 兜底 DB_API_<code>
77
78
  *
@@ -102,51 +103,70 @@ function mapDataloomBizError(code, rawMessage) {
102
103
  }
103
104
  return new error_1.AppError(`DB_API_${code}`, message);
104
105
  }
106
+ /**
107
+ * typo / CLI vocab violation 路径用:state 未知,列双 env 让用户在 dev/online 之间选,
108
+ * 不引导 init(init 不会创建 typo 出来的分支)。
109
+ */
110
+ exports.ENV_CTX_TYPO = {
111
+ available: ['dev', 'online'],
112
+ suggestInit: false,
113
+ };
105
114
  /**
106
115
  * 统一构造"--env 值不可用"错误。两类入口共用:
107
116
  * - CLI vocab 校验(_env.ts validateEnv):用户传 dev/main/online 以外值
108
117
  * - backend state 错(decorateEnvError):vocab 合法但 db 实际状态对不上
109
- * 两者用户角度都是「这个 env 不存在」,文案统一避免在两种失败之间困惑。
110
118
  *
111
- * `available` 推断逻辑:dev 不可用 主分支仍在,列 main/online;online/main 不可用
112
- * 罕见,列 dev 占位。不去查 backend,保持纯函数性。
119
+ * `available` `suggestInit` 由调用方按错误码归类传入;user-facing 不展示 `main`
120
+ * 内部别名,统一用 `online`。
113
121
  */
114
- function buildUnknownEnvError(env) {
115
- const available = env === 'dev' ? 'main, online' : 'dev';
122
+ function buildUnknownEnvError(env, ctx = exports.ENV_CTX_TYPO) {
123
+ const hints = [
124
+ `--env must match an existing database branch. Available: ${ctx.available.join(', ')}.`,
125
+ ];
126
+ if (ctx.suggestInit) {
127
+ hints.push(`Run \`miaoda db migration init\` before using '${env}'.`);
128
+ }
116
129
  return new error_1.AppError('UNKNOWN_ENV_VALUE', `Unknown --env value '${env}'`, {
117
- next_actions: [
118
- `--env must match an existing database branch. Available: ${available}.`,
119
- `Run \`miaoda db migration init\` before using '${env}'.`,
120
- ],
130
+ next_actions: hints,
121
131
  });
122
132
  }
123
133
  /**
124
- * 把 backend env 相关错误统一重写成 UNKNOWN_ENV_VALUE 文案。
134
+ * 把 backend env 相关错误统一重写成 UNKNOWN_ENV_VALUE 文案,按错误码做 state 推断:
125
135
  *
126
- * 命中条件:
127
- * - UNKNOWN_ENV_VALUE:上面 mapDataloomBizError k_dl_1600000 的封装,env 占位
128
- * server 返回的分支名,这里改写成用户实际传入的 --env
129
- * - DB_API_k_dl_1300039:dataloom requireExpertMultiEnv Multi-env not initialized
130
- * - DB_API_k_dl_000007 + "db branch not found":pg connection 层 ErrParamsInvalid
136
+ * - DB_API_k_dl_1300033(非专家应用)→ 单 env (online),不建议 init
137
+ * - DB_API_k_dl_1300039(专家未 init)→ env (online),建议 init
138
+ * - DB_API_k_dl_000007 + "db branch not found"(pg connection 兜底)→ 单 env,建议 init
139
+ * - UNKNOWN_ENV_VALUE(mapDataloomBizError k_dl_1600000 的占位)→ typo path
131
140
  *
132
- * env 未传时不改写:避免把 backend 兜底文案("Multi-env is not initialized")改成
133
- * `Unknown --env value ''` 这种空字符串错误。
141
+ * env 未传时不改写:避免把 backend 兜底文案(如 "Multi-env is not initialized"
142
+ * 改成 `Unknown --env value ''` 这种空字符串错误。
134
143
  */
135
144
  function decorateEnvError(err, env) {
136
145
  if (env === undefined || env === '')
137
146
  return err;
138
- if (!isEnvNotFoundError(err))
147
+ const ctx = classifyEnvError(err);
148
+ if (!ctx)
139
149
  return err;
140
- return buildUnknownEnvError(env);
150
+ return buildUnknownEnvError(env, ctx);
141
151
  }
142
- function isEnvNotFoundError(err) {
143
- if (err.code === 'UNKNOWN_ENV_VALUE')
144
- return true;
145
- if (err.code === 'DB_API_k_dl_1300039')
146
- return true;
147
- if (err.code === 'DB_API_k_dl_000007' && /db branch not found/i.test(err.message))
148
- return true;
149
- return false;
152
+ function classifyEnvError(err) {
153
+ if (err.code === 'DB_API_k_dl_1300033') {
154
+ // 非专家应用:init 也会被同一 guard 拒掉,建议 init 是误导
155
+ return { available: ['online'], suggestInit: false };
156
+ }
157
+ if (err.code === 'DB_API_k_dl_1300039') {
158
+ // 专家未 init:init 会创建 dev 分支
159
+ return { available: ['online'], suggestInit: true };
160
+ }
161
+ if (err.code === 'DB_API_k_dl_000007' && /db branch not found/i.test(err.message)) {
162
+ // pg connection 层 ErrParamsInvalid:大概率 pre-init;建议 init(非专家会被 init 路径拦)
163
+ return { available: ['online'], suggestInit: true };
164
+ }
165
+ if (err.code === 'UNKNOWN_ENV_VALUE') {
166
+ // mapDataloomBizError 对 k_dl_1600000 的占位:typo path,state 未知,列双 env
167
+ return exports.ENV_CTX_TYPO;
168
+ }
169
+ return null;
150
170
  }
151
171
  /**
152
172
  * 剥掉 PG 透传错误的 "ERROR:" 前缀:CLI 输出本身就会前缀 "Error:",
@@ -255,12 +275,25 @@ function buildInnerUrl(appId, path, query) {
255
275
  let url = `/v1/dataloom/app/${encodeURIComponent(appId)}${normalized}`;
256
276
  if (query) {
257
277
  const usp = new URLSearchParams();
258
- for (const [k, v] of Object.entries(query)) {
259
- if (v === undefined || v === '')
278
+ for (const [k, rawV] of Object.entries(query)) {
279
+ if (rawV === undefined)
280
+ continue;
281
+ // 数组值 → 重复 key 编码(?k=v1&k=v2)。IDL 里 list<string> 类型经
282
+ // Hertz/Kitex HTTP→Thrift 网关绑定 slice 字段需要重复 key;如果改成
283
+ // join(',') 单串,后端会拿到 ["v1,v2"] 单元素切片而非 ["v1","v2"]。
284
+ if (typeof rawV !== 'string') {
285
+ for (const item of rawV) {
286
+ if (item === '')
287
+ continue;
288
+ usp.append(k, item);
289
+ }
290
+ continue;
291
+ }
292
+ if (rawV === '')
260
293
  continue;
261
294
  // dbBranch 兼容用户视角的 `online` 别名 → 后端实际 dbBranch 名为 `main`,
262
295
  // 这里集中归一,避免每个 API 函数各自处理。其他值(dev / 自定义分支)原样透传。
263
- const norm = k === 'dbBranch' && v === 'online' ? 'main' : v;
296
+ const norm = k === 'dbBranch' && rawV === 'online' ? 'main' : rawV;
264
297
  usp.append(k, norm);
265
298
  }
266
299
  const qs = usp.toString();
@@ -203,20 +203,17 @@ async function runRecoveryPreview(appId, ts, rawTarget) {
203
203
  }
204
204
  // ── helpers ──
205
205
  /**
206
- * 把用户传入的 recovery target 格式化成 spinner / 日志展示用的紧凑字符串:
207
- * - 相对值(30s / 5m / 2h / 3d / 1w)→ 原样 + " ago",如 "20m ago"
208
- * - 绝对值 → 解析后用本地时区重新格式化成 ISO 8601 with offset,如
209
- * "2026-05-20T22:32:00+08:00"
210
- * - 解析失败 原样返回兜底
206
+ * 把用户传入的 recovery target 解析成本地时区的 ISO 8601 字符串,
207
+ * "2026-05-20T22:32:00+08:00"。无论用户传相对值(30m / 2h / 3d)还是绝对值,
208
+ * 都统一展示成"具体几点",让用户一眼看清楚"目标恢复点是我本地几点"——
209
+ * "30m ago"这种相对描述虽然原样直观,但跟 backend dataloom 收到的实际时间点没有
210
+ * 显式对照,遇到长 poll 时间过去后会让人怀疑"算的到底是哪个点"。
211
211
  *
212
- * 不直接用 normalizeTimestamp 的 UTC 字符串:UTC 'Z' 后缀对用户读时间不直观,
213
- * 本地时区带 offset 让用户一眼看清楚"目标恢复点是我本地几点"。
212
+ * 不用 UTC 'Z' 后缀:用户读时间不直观;带 +/-HH:MM offset 一眼即懂时差。
213
+ * 解析失败 原样返回兜底,避免 spinner 渲染崩。
214
214
  */
215
215
  function formatRecoveryTargetForDisplay(rawInput) {
216
216
  const trimmed = rawInput.trim();
217
- if (/^\d+[smhdw]$/i.test(trimmed)) {
218
- return `${trimmed} ago`;
219
- }
220
217
  let ms;
221
218
  try {
222
219
  ms = (0, time_1.parseTimeToMs)(trimmed);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/miaoda-cli",
3
- "version": "0.1.3-alpha.70f9b2d",
3
+ "version": "0.1.3-alpha.848d934",
4
4
  "description": "Miaoda 平台命令行工具,面向 Agent 调用",
5
5
  "type": "commonjs",
6
6
  "bin": {