dsh-db-tool 1.8.1 → 1.8.3
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/client/client.js +1 -1
- package/dist/adapters/sqlserver/index.js +18 -3
- package/dist/http/index.js +2 -1
- package/dist/manager.js +5 -4
- package/dist/store/transfer-history.js +7 -3
- package/dist/transfer.js +0 -1
- package/package.json +3 -3
package/client/client.js
CHANGED
|
@@ -3201,7 +3201,7 @@ window.__ModuleLoader__.load({
|
|
|
3201
3201
|
target: { conn: "", kind: "", db: "", mode: "" },
|
|
3202
3202
|
});
|
|
3203
3203
|
if (!yes) return;
|
|
3204
|
-
api("transfer-history/clear", { method: "POST", body: {} })
|
|
3204
|
+
api("transfer-history/clear", { method: "POST", body: { projectPath } })
|
|
3205
3205
|
.then((r) => { setMessage(t("ok") + " (" + (r && r.removed != null ? r.removed : 0) + ")"); setHistory([]); })
|
|
3206
3206
|
.catch((e) => setError(String(e && e.message ? e.message : e)));
|
|
3207
3207
|
}
|
|
@@ -382,8 +382,15 @@ function mssqlReason(e) {
|
|
|
382
382
|
// 默认 encrypt=true + trustServerCertificate=false 与 mssql 官方一致(不改默认值),但必须:
|
|
383
383
|
// 1) 不把「TCP 已连通、TLS 校验失败」误报成网络不可达(会把用户引向错误排查方向);
|
|
384
384
|
// 2) 把「怎么连上」写清楚(URL 加 ?trustServerCertificate=true / ?encrypt=false)。
|
|
385
|
-
|
|
386
|
-
|
|
385
|
+
// tedious 建连期把底层 socket/TLS 错误用 ES cause 选项挂在 err.cause(originalError 是 mssql 事务
|
|
386
|
+
// abort 专用,建连场景恒 undefined),message 已聚合底层原文但读 cause 更稳,一并纳入特征文本。
|
|
387
|
+
const causeText = errText(err.cause);
|
|
388
|
+
const tlsText = `${detail} ${errText(err.originalError)} ${causeText}`;
|
|
389
|
+
// 特征族来源:OpenSSL/BoringSSL 原生错误串(SSL routines/OPENSSL_internal/UNSUPPORTED_PROTOCOL、
|
|
390
|
+
// handshake_*.c)、Node ERR_SSL_NO_PROTOCOLS_AVAILABLE 的 message、服务器 alert 拒绝握手/版本。
|
|
391
|
+
// 刻意不加 ECONNRESET/socket hang up/ENOTFOUND——与真实网络故障不可区分,误加会让 ECONNREFUSED
|
|
392
|
+
// 场景被套上 TLS 指引。
|
|
393
|
+
const tlsish = /self[ -]?signed|certificate|unable to verify|wrong version number|ERR_SSL|EPROTO|CERT_|UNSUPPORTED_PROTOCOL|SSL[ -_]?routines|OPENSSL_internal|handshake[ _-]?(failure|client|server)|TLSV1_ALERT|SSLV3_ALERT|alert protocol version|alert handshake failure|no protocols available/i.test(tlsText);
|
|
387
394
|
let base;
|
|
388
395
|
switch (code) {
|
|
389
396
|
case 'ELOGIN':
|
|
@@ -399,7 +406,7 @@ function mssqlReason(e) {
|
|
|
399
406
|
// 保留「网络不可达」字样(既有断言与用户检索习惯依赖),但 TLS 特征时先说明 TCP 已连通
|
|
400
407
|
base = tlsish
|
|
401
408
|
? `TCP 已连通但 TLS 握手/证书校验失败(不是网络不可达:网络不可达指主机/端口不可达或连接被拒,此处 TCP 已建立)(${detail})`
|
|
402
|
-
: `网络不可达:无法与服务器建立 TCP
|
|
409
|
+
: `网络不可达:无法与服务器建立 TCP 连接,请检查主机名、端口与网络;端口确认可达仍反复出现时,也可能是服务器在 TLS 握手阶段主动断开(如老实例仅支持 TLS 1.0)(${detail})`;
|
|
403
410
|
break;
|
|
404
411
|
// 服务器强制加密(SQL Server 2022 / Azure SQL 默认)而客户端 encrypt=false:tedious 抛英文原文,
|
|
405
412
|
// 不映射则中文界面里只剩英文,故单列一条给出可直接照做的改法。
|
|
@@ -428,6 +435,14 @@ function mssqlReason(e) {
|
|
|
428
435
|
}
|
|
429
436
|
if (err.originalError !== undefined)
|
|
430
437
|
trail.push(`原始错误: ${errText(err.originalError)}`);
|
|
438
|
+
else if (err.cause !== undefined &&
|
|
439
|
+
err.cause !== null &&
|
|
440
|
+
errText(err.cause) !== detail &&
|
|
441
|
+
!detail.includes(errText(err.cause))) {
|
|
442
|
+
// 建连错误(ESOCKET 等)的底层错误在 cause 且已被 tedious 拼进 message 尾段;仅当
|
|
443
|
+
// message 未包含其全文(如被截断/包装)时补一条干净的底层错误,避免重复
|
|
444
|
+
trail.push(`原始错误: ${errText(err.cause)}`);
|
|
445
|
+
}
|
|
431
446
|
if (Array.isArray(err.precedingErrors) && err.precedingErrors.length > 0) {
|
|
432
447
|
trail.push(`前序错误: ${err.precedingErrors.map(errText).join('; ')}`);
|
|
433
448
|
}
|
package/dist/http/index.js
CHANGED
|
@@ -296,7 +296,8 @@ async function route(req, res, service, path, q, opts) {
|
|
|
296
296
|
return sendOk(res, service.transferHistory(projectOf(q), limit));
|
|
297
297
|
}
|
|
298
298
|
if (path === '/api/transfer-history/clear' && req.method === 'POST') {
|
|
299
|
-
|
|
299
|
+
const b = await readBody(req);
|
|
300
|
+
return sendOk(res, service.transferHistoryClear(projectOfBody(b)));
|
|
300
301
|
}
|
|
301
302
|
const transferMatch = /^\/api\/transfer\/([^/]+)(\/cancel)?$/.exec(path);
|
|
302
303
|
if (transferMatch) {
|
package/dist/manager.js
CHANGED
|
@@ -881,10 +881,11 @@ export class DbToolService {
|
|
|
881
881
|
? this.store.transferLog.tail(n, normalizeProjectKey(projectPath))
|
|
882
882
|
: this.store.transferLog.tail(n);
|
|
883
883
|
}
|
|
884
|
-
/**
|
|
885
|
-
transferHistoryClear() {
|
|
886
|
-
const
|
|
887
|
-
this.
|
|
884
|
+
/** 清除传输历史:projectPath 给定时只清该项目(前端文案语义),缺省全清。留审计。 */
|
|
885
|
+
transferHistoryClear(projectPath) {
|
|
886
|
+
const key = projectPath && projectPath.trim() !== '' ? normalizeProjectKey(projectPath) : undefined;
|
|
887
|
+
const removed = this.store.transferLog.clear(key);
|
|
888
|
+
this.audit(key ?? '', '', 'transfer_history_clear', key !== undefined ? `清除项目传输历史: ${key}` : '清除全部传输历史', 'none', false, true);
|
|
888
889
|
return { removed };
|
|
889
890
|
}
|
|
890
891
|
/** 清理终态任务(start 时调用;快照仅在 running 期间可查) */
|
|
@@ -89,8 +89,8 @@ export class TransferLog {
|
|
|
89
89
|
}
|
|
90
90
|
return out.reverse();
|
|
91
91
|
}
|
|
92
|
-
/**
|
|
93
|
-
clear() {
|
|
92
|
+
/** 清除日志;projectKey 给定时只删该项目条目,缺省全清。返回删除条数 */
|
|
93
|
+
clear(projectKey) {
|
|
94
94
|
if (!fs.existsSync(this.filePath))
|
|
95
95
|
return 0;
|
|
96
96
|
const lines = fs.readFileSync(this.filePath, 'utf8').split('\n');
|
|
@@ -101,7 +101,11 @@ export class TransferLog {
|
|
|
101
101
|
if (!t)
|
|
102
102
|
continue;
|
|
103
103
|
try {
|
|
104
|
-
JSON.parse(t);
|
|
104
|
+
const e = JSON.parse(t);
|
|
105
|
+
if (projectKey !== undefined && e.projectPathKey !== projectKey) {
|
|
106
|
+
kept.push(t); // 他项目条目原样保留
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
105
109
|
removed += 1;
|
|
106
110
|
}
|
|
107
111
|
catch {
|
package/dist/transfer.js
CHANGED
|
@@ -136,7 +136,6 @@ export function startTransferTask(source, target, opts) {
|
|
|
136
136
|
try {
|
|
137
137
|
prog.status = 'running';
|
|
138
138
|
emit({ type: 'table', status: 'running', table: name, rows: 0, totalRows: null });
|
|
139
|
-
emit({ type: 'table', status: 'running', table: name, rows: 0, totalRows: null });
|
|
140
139
|
const r = await createTransferReader(source, srcLoc);
|
|
141
140
|
reader = r; // 立即回填外层引用:writer 创建抛错时 finally 仍能关闭已打开的 reader
|
|
142
141
|
const w = await createTransferWriter(target, opts.writeMode, dstLoc);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-db-tool",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.3",
|
|
4
4
|
"description": "DSH community plugin: chat-operated multi-database admin tool with sidebar management, project-scoped grants, ro/rw modes and dangerous-operation confirmation",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -64,13 +64,13 @@
|
|
|
64
64
|
"@codemirror/language": "^6.12.4",
|
|
65
65
|
"@codemirror/state": "^6.7.6",
|
|
66
66
|
"@codemirror/view": "^6.43.13",
|
|
67
|
-
"@deepseek-ai/cordis": "^4.0.
|
|
67
|
+
"@deepseek-ai/cordis": "^4.0.5",
|
|
68
68
|
"@lezer/highlight": "^1.2.4",
|
|
69
69
|
"@stryker-mutator/core": "^10.0.0",
|
|
70
70
|
"@stryker-mutator/vitest-runner": "^10.0.0",
|
|
71
71
|
"@types/better-sqlite3": "latest",
|
|
72
72
|
"@types/node": "latest",
|
|
73
|
-
"dsh-better-sidebar": "^0.
|
|
73
|
+
"dsh-better-sidebar": "^0.28.0",
|
|
74
74
|
"esbuild": "^0.28.0",
|
|
75
75
|
"mongodb": "^7.6.0",
|
|
76
76
|
"mssql": "12.7.4",
|