@lark-apaas/miaoda-cli 0.1.3-alpha.4bf312e → 0.1.3-alpha.67da0bb
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/app/api.js +3 -3
- package/dist/api/app/schemas.js +43 -43
- package/dist/api/db/api.js +108 -112
- package/dist/api/db/client.js +41 -41
- package/dist/api/db/parsers.js +20 -20
- package/dist/api/db/sql-keywords.js +87 -87
- package/dist/api/deploy/api.js +5 -5
- package/dist/api/deploy/schemas.js +32 -32
- package/dist/api/file/api.js +74 -87
- package/dist/api/file/client.js +22 -22
- package/dist/api/file/detect.js +3 -3
- package/dist/api/file/parsers.js +18 -7
- package/dist/api/observability/api.js +6 -6
- package/dist/api/observability/schemas.js +14 -14
- package/dist/api/plugin/api.js +31 -31
- package/dist/cli/commands/app/index.js +12 -12
- package/dist/cli/commands/db/index.js +268 -163
- package/dist/cli/commands/deploy/index.js +28 -28
- package/dist/cli/commands/file/index.js +81 -61
- package/dist/cli/commands/observability/index.js +69 -69
- package/dist/cli/commands/plugin/index.js +27 -27
- package/dist/cli/commands/shared.js +10 -10
- package/dist/cli/handlers/app/update.js +2 -2
- package/dist/cli/handlers/db/audit.js +52 -43
- package/dist/cli/handlers/db/changelog.js +25 -12
- package/dist/cli/handlers/db/data.js +31 -30
- package/dist/cli/handlers/db/migration.js +27 -27
- package/dist/cli/handlers/db/quota.js +3 -3
- package/dist/cli/handlers/db/recovery.js +111 -82
- package/dist/cli/handlers/db/schema.js +33 -33
- package/dist/cli/handlers/db/sql.js +69 -69
- package/dist/cli/handlers/deploy/deploy.js +4 -4
- package/dist/cli/handlers/deploy/error-log.js +1 -1
- package/dist/cli/handlers/deploy/get.js +3 -3
- package/dist/cli/handlers/deploy/polling.js +11 -11
- package/dist/cli/handlers/file/cp.js +30 -30
- package/dist/cli/handlers/file/ls.js +5 -5
- package/dist/cli/handlers/file/quota.js +2 -2
- package/dist/cli/handlers/file/rm.js +24 -24
- package/dist/cli/handlers/file/sign.js +3 -3
- package/dist/cli/handlers/file/stat.js +10 -9
- package/dist/cli/handlers/observability/analytics.js +47 -47
- package/dist/cli/handlers/observability/helpers.js +2 -2
- package/dist/cli/handlers/observability/log.js +9 -9
- package/dist/cli/handlers/observability/metric.js +26 -26
- package/dist/cli/handlers/observability/trace.js +5 -5
- package/dist/cli/handlers/plugin/plugin-local.js +53 -53
- package/dist/cli/handlers/plugin/plugin.js +15 -15
- package/dist/cli/help.js +16 -16
- package/dist/main.js +12 -12
- package/dist/utils/args.js +1 -1
- package/dist/utils/colors.js +2 -2
- package/dist/utils/config.js +2 -2
- package/dist/utils/devops-error.js +9 -9
- package/dist/utils/error.js +2 -2
- package/dist/utils/git.js +4 -4
- package/dist/utils/http.js +19 -19
- package/dist/utils/output.js +47 -47
- package/dist/utils/poll.js +2 -2
- package/dist/utils/render.js +27 -27
- package/dist/utils/time.js +47 -42
- package/package.json +1 -1
package/dist/api/db/api.js
CHANGED
|
@@ -18,42 +18,28 @@ const http_1 = require("../../utils/http");
|
|
|
18
18
|
const error_1 = require("../../utils/error");
|
|
19
19
|
const http_client_1 = require("@lark-apaas/http-client");
|
|
20
20
|
const client_1 = require("./client");
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
* 1. 先尝试从 response body 解 envelope,命中 dataloom 业务 code → AppError
|
|
24
|
-
* 2. 兜底返 HttpError,保留真实 status 码与上下文
|
|
25
|
-
*
|
|
26
|
-
* 配合调用点的 try/catch + traceHttp,让 --verbose 在错误路径上也能拿到
|
|
27
|
-
* x-tt-logid 与 status,方便定位线上问题。
|
|
28
|
-
*/
|
|
29
|
-
async function mapDbHttpError(err, url, ctx,
|
|
30
|
-
/**
|
|
31
|
-
* 可选 hook:解析到响应 body 后,如果 envelope 命中业务错误并抛出 AppError,
|
|
32
|
-
* 调用方可以借此把 body 里的额外字段(如 multi-statement 的 partial results)
|
|
33
|
-
* 挂到 AppError 上。
|
|
34
|
-
*/
|
|
35
|
-
onErrorBody) {
|
|
21
|
+
const DEFAULT_TIMEOUT_HINT = 'The server may still be processing your request. Retry the command if needed.';
|
|
22
|
+
async function mapDbHttpError(err, url, ctx, opts) {
|
|
36
23
|
if (err instanceof error_1.AppError)
|
|
37
24
|
throw err;
|
|
38
25
|
// 客户端超时 / abort:SdkHttpError 时 response 通常缺失(status=0),落到 throw 时
|
|
39
|
-
// message 形如 'Failed to recover: 0' 让用户看不懂。识别 abort / timeout
|
|
40
|
-
//
|
|
26
|
+
// message 形如 'Failed to recover: 0' 让用户看不懂。识别 abort / timeout 关键字后
|
|
27
|
+
// 单独抛专用 AppError(带领域可定制的 message + hint),不再包成通用 "Failed to X"。
|
|
41
28
|
if (err instanceof Error) {
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
|
|
45
|
-
err.name ===
|
|
46
|
-
err.name ===
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
});
|
|
29
|
+
const lower = err.message.toLowerCase();
|
|
30
|
+
if (lower.includes('aborted') ||
|
|
31
|
+
lower.includes('timeout') ||
|
|
32
|
+
err.name === 'AbortError' ||
|
|
33
|
+
err.name === 'TimeoutError') {
|
|
34
|
+
const code = opts?.timeout?.code ?? 'REQUEST_TIMEOUT';
|
|
35
|
+
const message = opts?.timeout?.message ?? 'Request timed out after 30s';
|
|
36
|
+
const hint = opts?.timeout?.hint ?? DEFAULT_TIMEOUT_HINT;
|
|
37
|
+
throw new error_1.AppError(code, message, { next_actions: [hint] });
|
|
52
38
|
}
|
|
53
39
|
}
|
|
54
40
|
if (err instanceof http_client_1.HttpError) {
|
|
55
41
|
const status = err.response?.status ?? 0;
|
|
56
|
-
const statusText = err.response?.statusText ??
|
|
42
|
+
const statusText = err.response?.statusText ?? '';
|
|
57
43
|
try {
|
|
58
44
|
const body = (await err.response?.json());
|
|
59
45
|
if (body) {
|
|
@@ -61,8 +47,8 @@ onErrorBody) {
|
|
|
61
47
|
(0, client_1.extractData)(body); // 业务 code 命中 → 抛 AppError;不命中走兜底
|
|
62
48
|
}
|
|
63
49
|
catch (appErr) {
|
|
64
|
-
if (appErr instanceof error_1.AppError && onErrorBody) {
|
|
65
|
-
onErrorBody(body, appErr);
|
|
50
|
+
if (appErr instanceof error_1.AppError && opts?.onErrorBody) {
|
|
51
|
+
opts.onErrorBody(body, appErr);
|
|
66
52
|
}
|
|
67
53
|
throw appErr;
|
|
68
54
|
}
|
|
@@ -105,18 +91,28 @@ function attachSqlPartialResults(body, appErr) {
|
|
|
105
91
|
*/
|
|
106
92
|
async function execSql(opts) {
|
|
107
93
|
const client = (0, http_1.getHttpClient)();
|
|
108
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
94
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/sql', {
|
|
109
95
|
dbBranch: opts.dbBranch,
|
|
110
96
|
});
|
|
111
97
|
const start = Date.now();
|
|
112
98
|
let response;
|
|
113
99
|
try {
|
|
114
100
|
response = await client.post(url, { sql: opts.sql });
|
|
115
|
-
(0, client_1.traceHttp)(
|
|
101
|
+
(0, client_1.traceHttp)('POST', url, start, response);
|
|
116
102
|
}
|
|
117
103
|
catch (err) {
|
|
118
|
-
(0, client_1.traceHttp)(
|
|
119
|
-
await mapDbHttpError(err, url,
|
|
104
|
+
(0, client_1.traceHttp)('POST', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
105
|
+
await mapDbHttpError(err, url, 'Failed to execute SQL', {
|
|
106
|
+
onErrorBody: attachSqlPartialResults,
|
|
107
|
+
// SQL 路径单独的超时文案:PG 的 statement_timeout 会回滚整条事务,所以这里
|
|
108
|
+
// 明示「事务已回滚、没有改动落地」,并把 hint 引导到「简化 SQL / 加 LIMIT / 拆条」。
|
|
109
|
+
timeout: {
|
|
110
|
+
code: 'SQL_EXECUTION_TIMEOUT',
|
|
111
|
+
message: 'SQL execution timed out after 30s',
|
|
112
|
+
hint: 'The transaction was rolled back; no changes were applied. ' +
|
|
113
|
+
'Simplify the SQL, add filters or LIMIT for queries, or split it into smaller statements.',
|
|
114
|
+
},
|
|
115
|
+
});
|
|
120
116
|
throw err; // 不可达
|
|
121
117
|
}
|
|
122
118
|
const body = (await response.json());
|
|
@@ -127,11 +123,11 @@ async function execSql(opts) {
|
|
|
127
123
|
// results 末尾追加一条 SqlType="ERROR" 的哨兵,data 字段是 {code,message} JSON。
|
|
128
124
|
// 这样网关在错误路径不会吞业务字段,CLI 拿到完整 partial_results + statement_index。
|
|
129
125
|
const last = results.at(-1);
|
|
130
|
-
if (last?.sqlType ===
|
|
126
|
+
if (last?.sqlType === 'ERROR') {
|
|
131
127
|
const appErr = parseSqlErrorSentinel(last.data);
|
|
132
128
|
appErr.partial_results = results.slice(0, -1);
|
|
133
129
|
const stmtIdx = data.errorStatementIndex;
|
|
134
|
-
if (typeof stmtIdx ===
|
|
130
|
+
if (typeof stmtIdx === 'number')
|
|
135
131
|
appErr.statement_index = stmtIdx;
|
|
136
132
|
throw appErr;
|
|
137
133
|
}
|
|
@@ -163,12 +159,12 @@ async function execSql(opts) {
|
|
|
163
159
|
function parseSqlErrorSentinel(payload) {
|
|
164
160
|
try {
|
|
165
161
|
const parsed = JSON.parse(payload);
|
|
166
|
-
const code = typeof parsed.code ===
|
|
167
|
-
const message = typeof parsed.message ===
|
|
162
|
+
const code = typeof parsed.code === 'string' && parsed.code !== '' ? parsed.code : 'INTERNAL_DB_ERROR';
|
|
163
|
+
const message = typeof parsed.message === 'string' ? parsed.message : payload;
|
|
168
164
|
return (0, client_1.mapDataloomBizError)(code, message);
|
|
169
165
|
}
|
|
170
166
|
catch {
|
|
171
|
-
return new error_1.AppError(
|
|
167
|
+
return new error_1.AppError('INTERNAL_DB_ERROR', payload);
|
|
172
168
|
}
|
|
173
169
|
}
|
|
174
170
|
// ── db schema → InnerGetSchema ──
|
|
@@ -180,21 +176,21 @@ function parseSqlErrorSentinel(payload) {
|
|
|
180
176
|
*/
|
|
181
177
|
async function getSchema(opts) {
|
|
182
178
|
const client = (0, http_1.getHttpClient)();
|
|
183
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
184
|
-
format: opts.format ??
|
|
179
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/schema', {
|
|
180
|
+
format: opts.format ?? 'schema',
|
|
185
181
|
tableNames: opts.tableNames,
|
|
186
|
-
includeStats: opts.includeStats ?
|
|
182
|
+
includeStats: opts.includeStats ? 'true' : undefined,
|
|
187
183
|
dbBranch: opts.dbBranch,
|
|
188
184
|
});
|
|
189
185
|
const start = Date.now();
|
|
190
186
|
let response;
|
|
191
187
|
try {
|
|
192
188
|
response = await client.get(url);
|
|
193
|
-
(0, client_1.traceHttp)(
|
|
189
|
+
(0, client_1.traceHttp)('GET', url, start, response);
|
|
194
190
|
}
|
|
195
191
|
catch (err) {
|
|
196
|
-
(0, client_1.traceHttp)(
|
|
197
|
-
await mapDbHttpError(err, url,
|
|
192
|
+
(0, client_1.traceHttp)('GET', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
193
|
+
await mapDbHttpError(err, url, 'Failed to get schema');
|
|
198
194
|
throw err; // 不可达
|
|
199
195
|
}
|
|
200
196
|
const body = (await response.json());
|
|
@@ -214,24 +210,24 @@ async function getSchema(opts) {
|
|
|
214
210
|
*/
|
|
215
211
|
async function importData(opts) {
|
|
216
212
|
const client = (0, http_1.getHttpClient)();
|
|
217
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
213
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/data/import');
|
|
218
214
|
const reqBody = {
|
|
219
215
|
tableName: opts.tableName,
|
|
220
216
|
format: opts.format,
|
|
221
|
-
records: opts.body.toString(
|
|
217
|
+
records: opts.body.toString('utf8'),
|
|
222
218
|
};
|
|
223
|
-
if (opts.dbBranch !== undefined && opts.dbBranch !==
|
|
219
|
+
if (opts.dbBranch !== undefined && opts.dbBranch !== '') {
|
|
224
220
|
reqBody.dbBranch = opts.dbBranch;
|
|
225
221
|
}
|
|
226
222
|
const start = Date.now();
|
|
227
223
|
let response;
|
|
228
224
|
try {
|
|
229
225
|
response = await client.post(url, reqBody);
|
|
230
|
-
(0, client_1.traceHttp)(
|
|
226
|
+
(0, client_1.traceHttp)('POST', url, start, response);
|
|
231
227
|
}
|
|
232
228
|
catch (err) {
|
|
233
|
-
(0, client_1.traceHttp)(
|
|
234
|
-
await mapDbHttpError(err, url,
|
|
229
|
+
(0, client_1.traceHttp)('POST', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
230
|
+
await mapDbHttpError(err, url, 'Failed to import data');
|
|
235
231
|
throw err; // 不可达
|
|
236
232
|
}
|
|
237
233
|
// 后端 InnerAdminImportData 响应里 data 直接返 {tableName, recordCount, durationMs}
|
|
@@ -255,7 +251,7 @@ async function importData(opts) {
|
|
|
255
251
|
*/
|
|
256
252
|
async function exportData(opts) {
|
|
257
253
|
const client = (0, http_1.getHttpClient)();
|
|
258
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
254
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/data/export', {
|
|
259
255
|
tableName: opts.tableName,
|
|
260
256
|
format: opts.format,
|
|
261
257
|
limit: String(opts.limit ?? 5000),
|
|
@@ -265,35 +261,35 @@ async function exportData(opts) {
|
|
|
265
261
|
const start = Date.now();
|
|
266
262
|
let response;
|
|
267
263
|
try {
|
|
268
|
-
response = await client.request({ method:
|
|
269
|
-
(0, client_1.traceHttp)(
|
|
264
|
+
response = await client.request({ method: 'POST', url });
|
|
265
|
+
(0, client_1.traceHttp)('POST', url, start, response);
|
|
270
266
|
}
|
|
271
267
|
catch (err) {
|
|
272
|
-
(0, client_1.traceHttp)(
|
|
273
|
-
await mapDbHttpError(err, url,
|
|
268
|
+
(0, client_1.traceHttp)('POST', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
269
|
+
await mapDbHttpError(err, url, 'Failed to export data');
|
|
274
270
|
throw err; // 不可达
|
|
275
271
|
}
|
|
276
272
|
// 成功路径:响应 body 通常是原始 CSV/SQL/JSON 字节,但部分错误场景下网关会返
|
|
277
273
|
// HTTP 200 + JSON envelope(status_code != "0"),需要在这里嗅探兜底。
|
|
278
274
|
const defaultContentType = {
|
|
279
|
-
csv:
|
|
280
|
-
sql:
|
|
281
|
-
json:
|
|
275
|
+
csv: 'text/csv',
|
|
276
|
+
sql: 'text/plain',
|
|
277
|
+
json: 'application/json',
|
|
282
278
|
};
|
|
283
|
-
const contentType = response.headers.get(
|
|
279
|
+
const contentType = response.headers.get('Content-Type') ?? defaultContentType[opts.format];
|
|
284
280
|
const ab = await response.arrayBuffer();
|
|
285
281
|
const buf = Buffer.from(new Uint8Array(ab));
|
|
286
282
|
if (buf.length === 0) {
|
|
287
|
-
throw new error_1.AppError(
|
|
283
|
+
throw new error_1.AppError('INTERNAL_DB_ERROR', 'Empty export response body');
|
|
288
284
|
}
|
|
289
285
|
// Envelope sniff:HTTP 200 + Content-Type 为 application/json + body 解析得到
|
|
290
286
|
// InnerEnvelope 且 status_code 非 "0" 时,按业务错误抛出。
|
|
291
287
|
// CSV / SQL 都是非 JSON 输出,application/json 响应必是错误信封;JSON 格式
|
|
292
288
|
// 成功响应自身就是 application/json,跳过 sniff 避免误判。
|
|
293
|
-
if (opts.format !==
|
|
289
|
+
if (opts.format !== 'json' && /application\/json/i.test(contentType)) {
|
|
294
290
|
try {
|
|
295
|
-
const parsed = JSON.parse(buf.toString(
|
|
296
|
-
if (parsed.status_code != null && parsed.status_code !==
|
|
291
|
+
const parsed = JSON.parse(buf.toString('utf8'));
|
|
292
|
+
if (parsed.status_code != null && parsed.status_code !== '0') {
|
|
297
293
|
// 复用 extractData 的错误映射逻辑(throw AppError)
|
|
298
294
|
(0, client_1.extractData)(parsed);
|
|
299
295
|
}
|
|
@@ -306,7 +302,7 @@ async function exportData(opts) {
|
|
|
306
302
|
}
|
|
307
303
|
}
|
|
308
304
|
// 后端通过响应头回传记录数(避免污染 body);header 缺失或解析失败 → undefined
|
|
309
|
-
const recordCountHeader = response.headers.get(
|
|
305
|
+
const recordCountHeader = response.headers.get('X-Miaoda-Record-Count');
|
|
310
306
|
const parsedCount = recordCountHeader != null ? Number(recordCountHeader) : NaN;
|
|
311
307
|
const recordCount = Number.isFinite(parsedCount) && parsedCount >= 0 ? parsedCount : undefined;
|
|
312
308
|
return {
|
|
@@ -325,7 +321,7 @@ async function exportData(opts) {
|
|
|
325
321
|
*/
|
|
326
322
|
async function listDDLChangelog(opts) {
|
|
327
323
|
const client = (0, http_1.getHttpClient)();
|
|
328
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
324
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/changelog', {
|
|
329
325
|
table: opts.table,
|
|
330
326
|
since: opts.since,
|
|
331
327
|
until: opts.until,
|
|
@@ -337,18 +333,18 @@ async function listDDLChangelog(opts) {
|
|
|
337
333
|
let response;
|
|
338
334
|
try {
|
|
339
335
|
response = await client.get(url);
|
|
340
|
-
(0, client_1.traceHttp)(
|
|
336
|
+
(0, client_1.traceHttp)('GET', url, start, response);
|
|
341
337
|
}
|
|
342
338
|
catch (err) {
|
|
343
|
-
(0, client_1.traceHttp)(
|
|
344
|
-
await mapDbHttpError(err, url,
|
|
339
|
+
(0, client_1.traceHttp)('GET', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
340
|
+
await mapDbHttpError(err, url, 'Failed to list DDL changelog');
|
|
345
341
|
throw err; // 不可达
|
|
346
342
|
}
|
|
347
343
|
const body = (await response.json());
|
|
348
344
|
const data = (0, client_1.extractData)(body);
|
|
349
345
|
return {
|
|
350
346
|
items: data.items ?? [],
|
|
351
|
-
nextCursor: data.nextCursor && data.nextCursor !==
|
|
347
|
+
nextCursor: data.nextCursor && data.nextCursor !== '' ? data.nextCursor : null,
|
|
352
348
|
hasMore: Boolean(data.hasMore),
|
|
353
349
|
};
|
|
354
350
|
}
|
|
@@ -359,7 +355,7 @@ async function listDDLChangelog(opts) {
|
|
|
359
355
|
*/
|
|
360
356
|
async function getAuditStatus(opts) {
|
|
361
357
|
const client = (0, http_1.getHttpClient)();
|
|
362
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
358
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/audit/status', {
|
|
363
359
|
table: opts.table,
|
|
364
360
|
dbBranch: opts.dbBranch,
|
|
365
361
|
});
|
|
@@ -367,11 +363,11 @@ async function getAuditStatus(opts) {
|
|
|
367
363
|
let response;
|
|
368
364
|
try {
|
|
369
365
|
response = await client.get(url);
|
|
370
|
-
(0, client_1.traceHttp)(
|
|
366
|
+
(0, client_1.traceHttp)('GET', url, start, response);
|
|
371
367
|
}
|
|
372
368
|
catch (err) {
|
|
373
|
-
(0, client_1.traceHttp)(
|
|
374
|
-
await mapDbHttpError(err, url,
|
|
369
|
+
(0, client_1.traceHttp)('GET', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
370
|
+
await mapDbHttpError(err, url, 'Failed to get audit status');
|
|
375
371
|
throw err; // 不可达
|
|
376
372
|
}
|
|
377
373
|
const respBody = (await response.json());
|
|
@@ -384,30 +380,30 @@ async function getAuditStatus(opts) {
|
|
|
384
380
|
*/
|
|
385
381
|
async function setAuditConfig(opts) {
|
|
386
382
|
const client = (0, http_1.getHttpClient)();
|
|
387
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
383
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/audit/config');
|
|
388
384
|
const body = {
|
|
389
385
|
table: opts.table,
|
|
390
386
|
enabled: opts.enabled,
|
|
391
387
|
};
|
|
392
|
-
if (opts.retention !== undefined && opts.retention !==
|
|
388
|
+
if (opts.retention !== undefined && opts.retention !== '')
|
|
393
389
|
body.retention = opts.retention;
|
|
394
|
-
if (opts.dbBranch !== undefined && opts.dbBranch !==
|
|
390
|
+
if (opts.dbBranch !== undefined && opts.dbBranch !== '')
|
|
395
391
|
body.dbBranch = opts.dbBranch;
|
|
396
392
|
const start = Date.now();
|
|
397
393
|
let response;
|
|
398
394
|
try {
|
|
399
395
|
response = await client.post(url, body);
|
|
400
|
-
(0, client_1.traceHttp)(
|
|
396
|
+
(0, client_1.traceHttp)('POST', url, start, response);
|
|
401
397
|
}
|
|
402
398
|
catch (err) {
|
|
403
|
-
(0, client_1.traceHttp)(
|
|
404
|
-
await mapDbHttpError(err, url,
|
|
399
|
+
(0, client_1.traceHttp)('POST', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
400
|
+
await mapDbHttpError(err, url, 'Failed to set audit config');
|
|
405
401
|
throw err; // 不可达
|
|
406
402
|
}
|
|
407
403
|
const respBody = (await response.json());
|
|
408
404
|
const data = (0, client_1.extractData)(respBody);
|
|
409
405
|
if (!data.status) {
|
|
410
|
-
throw new error_1.AppError(
|
|
406
|
+
throw new error_1.AppError('INTERNAL_DB_ERROR', 'audit config response missing status field');
|
|
411
407
|
}
|
|
412
408
|
return data.status;
|
|
413
409
|
}
|
|
@@ -425,11 +421,11 @@ async function setAuditConfig(opts) {
|
|
|
425
421
|
*/
|
|
426
422
|
async function listAuditLog(opts) {
|
|
427
423
|
if (opts.tables.length === 0) {
|
|
428
|
-
throw new error_1.AppError(
|
|
424
|
+
throw new error_1.AppError('ARGS_INVALID', 'at least one table is required');
|
|
429
425
|
}
|
|
430
426
|
const client = (0, http_1.getHttpClient)();
|
|
431
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
432
|
-
tables: opts.tables.join(
|
|
427
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/audit/log', {
|
|
428
|
+
tables: opts.tables.join(','),
|
|
433
429
|
since: opts.since,
|
|
434
430
|
until: opts.until,
|
|
435
431
|
limit: opts.limit !== undefined ? String(opts.limit) : undefined,
|
|
@@ -440,18 +436,18 @@ async function listAuditLog(opts) {
|
|
|
440
436
|
let response;
|
|
441
437
|
try {
|
|
442
438
|
response = await client.get(url);
|
|
443
|
-
(0, client_1.traceHttp)(
|
|
439
|
+
(0, client_1.traceHttp)('GET', url, start, response);
|
|
444
440
|
}
|
|
445
441
|
catch (err) {
|
|
446
|
-
(0, client_1.traceHttp)(
|
|
447
|
-
await mapDbHttpError(err, url,
|
|
442
|
+
(0, client_1.traceHttp)('GET', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
443
|
+
await mapDbHttpError(err, url, 'Failed to list audit log');
|
|
448
444
|
throw err; // 不可达
|
|
449
445
|
}
|
|
450
446
|
const body = (await response.json());
|
|
451
447
|
const data = (0, client_1.extractData)(body);
|
|
452
448
|
return {
|
|
453
449
|
items: data.items ?? [],
|
|
454
|
-
nextCursor: data.nextCursor && data.nextCursor !==
|
|
450
|
+
nextCursor: data.nextCursor && data.nextCursor !== '' ? data.nextCursor : null,
|
|
455
451
|
hasMore: Boolean(data.hasMore),
|
|
456
452
|
skipped: data.skipped ?? [],
|
|
457
453
|
};
|
|
@@ -463,7 +459,7 @@ async function listAuditLog(opts) {
|
|
|
463
459
|
*/
|
|
464
460
|
async function migrationInit(opts) {
|
|
465
461
|
const client = (0, http_1.getHttpClient)();
|
|
466
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
462
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/enableMultiEnv');
|
|
467
463
|
const body = {};
|
|
468
464
|
if (opts.syncData !== undefined)
|
|
469
465
|
body.syncData = opts.syncData;
|
|
@@ -471,11 +467,11 @@ async function migrationInit(opts) {
|
|
|
471
467
|
let response;
|
|
472
468
|
try {
|
|
473
469
|
response = await client.post(url, body);
|
|
474
|
-
(0, client_1.traceHttp)(
|
|
470
|
+
(0, client_1.traceHttp)('POST', url, start, response);
|
|
475
471
|
}
|
|
476
472
|
catch (err) {
|
|
477
|
-
(0, client_1.traceHttp)(
|
|
478
|
-
await mapDbHttpError(err, url,
|
|
473
|
+
(0, client_1.traceHttp)('POST', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
474
|
+
await mapDbHttpError(err, url, 'Failed to init migration');
|
|
479
475
|
throw err; // 不可达
|
|
480
476
|
}
|
|
481
477
|
const respBody = (await response.json());
|
|
@@ -487,16 +483,16 @@ async function migrationInit(opts) {
|
|
|
487
483
|
*/
|
|
488
484
|
async function migrate(opts) {
|
|
489
485
|
const client = (0, http_1.getHttpClient)();
|
|
490
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
486
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/migration');
|
|
491
487
|
const start = Date.now();
|
|
492
488
|
let response;
|
|
493
489
|
try {
|
|
494
490
|
response = await client.post(url, { dryRun: opts.dryRun });
|
|
495
|
-
(0, client_1.traceHttp)(
|
|
491
|
+
(0, client_1.traceHttp)('POST', url, start, response);
|
|
496
492
|
}
|
|
497
493
|
catch (err) {
|
|
498
|
-
(0, client_1.traceHttp)(
|
|
499
|
-
await mapDbHttpError(err, url,
|
|
494
|
+
(0, client_1.traceHttp)('POST', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
495
|
+
await mapDbHttpError(err, url, 'Failed to migrate');
|
|
500
496
|
throw err; // 不可达
|
|
501
497
|
}
|
|
502
498
|
const respBody = (await response.json());
|
|
@@ -509,7 +505,7 @@ async function migrate(opts) {
|
|
|
509
505
|
*/
|
|
510
506
|
async function getMigrationStatus(opts) {
|
|
511
507
|
const client = (0, http_1.getHttpClient)();
|
|
512
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
508
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/migration/status', {
|
|
513
509
|
taskId: opts.taskId,
|
|
514
510
|
dbBranch: opts.dbBranch,
|
|
515
511
|
});
|
|
@@ -517,11 +513,11 @@ async function getMigrationStatus(opts) {
|
|
|
517
513
|
let response;
|
|
518
514
|
try {
|
|
519
515
|
response = await client.get(url);
|
|
520
|
-
(0, client_1.traceHttp)(
|
|
516
|
+
(0, client_1.traceHttp)('GET', url, start, response);
|
|
521
517
|
}
|
|
522
518
|
catch (err) {
|
|
523
|
-
(0, client_1.traceHttp)(
|
|
524
|
-
await mapDbHttpError(err, url,
|
|
519
|
+
(0, client_1.traceHttp)('GET', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
520
|
+
await mapDbHttpError(err, url, 'Failed to get migration status');
|
|
525
521
|
throw err; // 不可达
|
|
526
522
|
}
|
|
527
523
|
const body = (await response.json());
|
|
@@ -534,7 +530,7 @@ async function getMigrationStatus(opts) {
|
|
|
534
530
|
*/
|
|
535
531
|
async function recover(opts) {
|
|
536
532
|
const client = (0, http_1.getHttpClient)();
|
|
537
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
533
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/recovery');
|
|
538
534
|
const start = Date.now();
|
|
539
535
|
let response;
|
|
540
536
|
try {
|
|
@@ -542,11 +538,11 @@ async function recover(opts) {
|
|
|
542
538
|
target: opts.target,
|
|
543
539
|
dryRun: opts.dryRun,
|
|
544
540
|
});
|
|
545
|
-
(0, client_1.traceHttp)(
|
|
541
|
+
(0, client_1.traceHttp)('POST', url, start, response);
|
|
546
542
|
}
|
|
547
543
|
catch (err) {
|
|
548
|
-
(0, client_1.traceHttp)(
|
|
549
|
-
await mapDbHttpError(err, url,
|
|
544
|
+
(0, client_1.traceHttp)('POST', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
545
|
+
await mapDbHttpError(err, url, 'Failed to recover');
|
|
550
546
|
throw err; // 不可达
|
|
551
547
|
}
|
|
552
548
|
const respBody = (await response.json());
|
|
@@ -558,7 +554,7 @@ async function recover(opts) {
|
|
|
558
554
|
*/
|
|
559
555
|
async function getRecoveryPreview(opts) {
|
|
560
556
|
const client = (0, http_1.getHttpClient)();
|
|
561
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
557
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/recovery/preview', {
|
|
562
558
|
previewRequestId: opts.previewRequestId,
|
|
563
559
|
dbBranch: opts.dbBranch,
|
|
564
560
|
});
|
|
@@ -566,11 +562,11 @@ async function getRecoveryPreview(opts) {
|
|
|
566
562
|
let response;
|
|
567
563
|
try {
|
|
568
564
|
response = await client.get(url);
|
|
569
|
-
(0, client_1.traceHttp)(
|
|
565
|
+
(0, client_1.traceHttp)('GET', url, start, response);
|
|
570
566
|
}
|
|
571
567
|
catch (err) {
|
|
572
|
-
(0, client_1.traceHttp)(
|
|
573
|
-
await mapDbHttpError(err, url,
|
|
568
|
+
(0, client_1.traceHttp)('GET', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
569
|
+
await mapDbHttpError(err, url, 'Failed to get recovery preview');
|
|
574
570
|
throw err; // 不可达
|
|
575
571
|
}
|
|
576
572
|
const body = (await response.json());
|
|
@@ -582,16 +578,16 @@ async function getRecoveryPreview(opts) {
|
|
|
582
578
|
*/
|
|
583
579
|
async function getDbQuota(opts) {
|
|
584
580
|
const client = (0, http_1.getHttpClient)();
|
|
585
|
-
const url = (0, client_1.buildInnerUrl)(opts.appId,
|
|
581
|
+
const url = (0, client_1.buildInnerUrl)(opts.appId, '/db/quota', { dbBranch: opts.dbBranch });
|
|
586
582
|
const start = Date.now();
|
|
587
583
|
let response;
|
|
588
584
|
try {
|
|
589
585
|
response = await client.get(url);
|
|
590
|
-
(0, client_1.traceHttp)(
|
|
586
|
+
(0, client_1.traceHttp)('GET', url, start, response);
|
|
591
587
|
}
|
|
592
588
|
catch (err) {
|
|
593
|
-
(0, client_1.traceHttp)(
|
|
594
|
-
await mapDbHttpError(err, url,
|
|
589
|
+
(0, client_1.traceHttp)('GET', url, start, err instanceof http_client_1.HttpError ? err.response : undefined, err);
|
|
590
|
+
await mapDbHttpError(err, url, 'Failed to get db quota');
|
|
595
591
|
throw err; // 不可达
|
|
596
592
|
}
|
|
597
593
|
const respBody = (await response.json());
|