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 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
- const tlsText = `${detail} ${errText(err.originalError)}`;
386
- const tlsish = /self[ -]?signed|certificate|unable to verify|wrong version number|ERR_SSL|EPROTO|CERT_/i.test(tlsText);
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 连接,请检查主机名、端口与网络(${detail})`;
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
  }
@@ -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
- return sendOk(res, service.transferHistoryClear());
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 removed = this.store.transferLog.clear();
887
- this.audit('', '', 'transfer_history_clear', '清除全部传输历史', 'none', false, true);
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.1",
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.4",
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.24.1",
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",