dsh-email 0.16.2 → 0.17.0

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/CHANGELOG.md CHANGED
@@ -4,6 +4,15 @@
4
4
 
5
5
  [历史英文记录](docs/CHANGELOG.en.md)
6
6
 
7
+ ## 0.17.0(2026-10-17)
8
+
9
+ - 设置面板顶部新增「首次使用」分步引导:一次只讲一步,支持上一步/下一步/跳过,看完记在本机不再出现。
10
+ - 引导内容与该插件的实际用法一致;可在开发者工具里清掉 `dsh-first-run:dsh-email:v1` 重新查看。
11
+ ## 0.16.3 (2026-10-17)
12
+
13
+ - 修复未配置邮箱时,服务商示例列表被凭据脱敏器误隐藏的问题;保留真实凭据的原有脱敏规则。
14
+ - 增加配置错误经过脱敏后的回归;在官方 DSH 0.2.1-alpha.5 中复测本地草稿、附件、明确确认与本机 SMTP 回执。
15
+
7
16
  ## 0.16.2 (2026-10-08)
8
17
 
9
18
  - Windows 的 OAuth2 access / refresh token 改用当前用户 DPAPI 加密,旧的有效令牌自动原位迁移;不使用明文备份、命令参数或临时明文文件传输令牌。
package/README.en.md CHANGED
@@ -10,6 +10,9 @@ Read, send, search and organize email from DSH with multiple accounts.
10
10
 
11
11
  Feedback and contributions are welcome: report [issues](https://github.com/STARDUSTLC666/dsh-email/issues) or submit [pull requests](https://github.com/STARDUSTLC666/dsh-email/pulls).
12
12
 
13
+
14
+ See the [0.16.3 validation record](docs/validation/0.16.3.md) for DSH `0.2.1-alpha.5` browser checks and the remaining limits.
15
+
13
16
  ## What it does
14
17
 
15
18
  - Read, send, reply and forward using IMAP and SMTP.
package/README.md CHANGED
@@ -10,6 +10,9 @@
10
10
 
11
11
  欢迎使用,遇到问题或有改进建议,请提交 [issues](https://github.com/STARDUSTLC666/dsh-email/issues) 和 [PR](https://github.com/STARDUSTLC666/dsh-email/pulls)。
12
12
 
13
+
14
+ DSH `0.2.1-alpha.5` 的本轮检查与未验收范围见 [0.16.3 验收记录](docs/validation/0.16.3.md)。
15
+
13
16
  ## 功能
14
17
 
15
18
  - 通过 IMAP / SMTP 收发、回复和转发邮件。
@@ -1,5 +1,7 @@
1
1
  # dsh-email 验证记录
2
2
 
3
+ [0.16.3 · DSH 0.2.1-alpha.5 浏览器操作验收](validation/0.16.3.md)。
4
+
3
5
  [0.16.2 Windows 令牌加密与迁移验收](validation/0.16.2.md)。
4
6
 
5
7
  [0.16.1 会话附件与发信策略验收](validation/0.16.1.md)。
@@ -0,0 +1,10 @@
1
+ # 0.16.3 · DSH alpha.5 网页验收
2
+
3
+ 宿主为公开 npm `@deepseek-ai/dsh@0.2.1-alpha.5`,Windows Node 24,系统 Chrome 无头浏览器。使用独立 profile、合成邮箱与只监听回环地址的 SMTP 服务。
4
+
5
+ - 347 项 Windows 自动测试通过,包含配置错误通过凭据脱敏后仍保留服务商选择的回归。真实 JWT、XOAUTH2 字符串和密码的脱敏测试继续通过。
6
+ - 未配置账号时可以保存本地草稿,发送预览明确报出缺失配置;服务商名称可以正常阅读。
7
+ - 实际点击/输入完成新草稿、账号选择、To、主题、正文、附件上传、发送预览、勾选核对与明确提交。
8
+ - 本机 SMTP 接收到唯一一次提交及附件;已发送草稿没有再次发送入口,复制得到独立未发送草稿。SMTP 回执不等于投递到真实收件箱。
9
+
10
+ 未连接真实 IMAP、SMTP 或 OAuth 租户,未操作桌面原生窗口。
package/lib/client.js CHANGED
@@ -9,6 +9,71 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  const React = require("react");
10
10
  const { useState, useEffect, useCallback, useRef } = React;
11
11
  const h = React.createElement;
12
+ const __FR_KEY = 'dsh-first-run:dsh-email:v1';
13
+ const __FR_TITLE = '邮件 · 首次使用(4 步)';
14
+ const __FR_STEPS = [
15
+ { title: '先把账号填上', body: '下面填 IMAP / SMTP 地址与授权码(QQ 邮箱用「授权码」,不是登录密码)。保存后这里会显示连接状态。' },
16
+ { title: '看一眼收件箱', body: '连接成功后,下方会列出最近邮件的标题与发件人;点开任意一封可读正文。' },
17
+ { title: '让它替你整理', body: '在对话里直接说你要做的事,比在页面里逐个点更快。', tryIt: '把今天的未读邮件按主题归纳一下' },
18
+ { title: '发信前一定先看草稿', body: '涉及发信时默认先生成草稿给你确认,确认后才真正发送;收件人规则在下方「发信规则」里配。' },
19
+ ];
20
+
21
+ // ---- first-run guide (shared snippet, keep in sync across plugins) ----
22
+ const __FR_STYLE_ID = 'dsh-first-run-css';
23
+ const __FR_CSS = [
24
+ '.fr-card{border:1px solid var(--dsw-border,rgba(0,0,0,.10));border-radius:12px;padding:14px 16px;margin:0 0 14px;background:linear-gradient(180deg,rgba(59,130,246,.06),rgba(59,130,246,.02))}',
25
+ '.fr-head{display:flex;align-items:center;gap:8px;margin-bottom:6px}',
26
+ '.fr-dot{width:6px;height:6px;border-radius:50%;background:var(--dsw-accent,#3b82f6)}',
27
+ '.fr-title{font-weight:650;font-size:13.5px}',
28
+ '.fr-count{margin-left:auto;font-size:11px;color:var(--dsw-text-weak,#6b7280);font-variant-numeric:tabular-nums}',
29
+ '.fr-step{font-weight:600;font-size:13px;margin:2px 0 4px}',
30
+ '.fr-body{color:var(--dsw-text-weak,#4b5563);font-size:12.5px;line-height:1.65}',
31
+ '.fr-try{margin-top:8px;padding:7px 9px;border-radius:8px;background:rgba(59,130,246,.09);font-size:12px;display:flex;gap:8px}',
32
+ '.fr-try code{font-family:ui-monospace,monospace;white-space:pre-wrap;word-break:break-word}',
33
+ '.fr-bar{display:flex;gap:8px;align-items:center;margin-top:12px}',
34
+ '.fr-progress{display:flex;gap:4px;margin-right:auto}',
35
+ '.fr-seg{width:16px;height:3px;border-radius:2px;background:var(--dsw-border,rgba(0,0,0,.12))}',
36
+ '.fr-seg.on{background:var(--dsw-accent,#3b82f6)}',
37
+ '.fr-btn{border:1px solid var(--dsw-border,rgba(0,0,0,.14));background:transparent;color:inherit;border-radius:8px;padding:4px 10px;font-size:12px;cursor:pointer}',
38
+ '.fr-btn:hover{background:rgba(0,0,0,.04)}',
39
+ '.fr-btn.primary{background:var(--dsw-accent,#3b82f6);border-color:transparent;color:#fff}',
40
+ '.fr-btn.ghost{border-color:transparent;color:var(--dsw-text-weak,#6b7280)}',
41
+ ].join('\n');
42
+ function __frEnsureCss() {
43
+ if (document.getElementById(__FR_STYLE_ID)) return;
44
+ const el = document.createElement('style');
45
+ el.id = __FR_STYLE_ID;
46
+ el.textContent = __FR_CSS;
47
+ document.head.appendChild(el);
48
+ }
49
+ function __frRead() { try { return localStorage.getItem(__FR_KEY) === 'done'; } catch { return false; } }
50
+ function __frWrite() { try { localStorage.setItem(__FR_KEY, 'done'); } catch {} }
51
+ function __FirstRunCard() {
52
+ const [done, setDone] = React.useState(__frRead);
53
+ const [index, setIndex] = React.useState(0);
54
+ React.useEffect(() => { __frEnsureCss(); }, []);
55
+ if (done) return null;
56
+ const step = __FR_STEPS[index];
57
+ const last = index >= __FR_STEPS.length - 1;
58
+ const close = () => { __frWrite(); setDone(true); };
59
+ return h('div', { className: 'fr-card' },
60
+ h('div', { className: 'fr-head' }, h('span', { className: 'fr-dot' }), h('span', { className: 'fr-title' }, __FR_TITLE), h('span', { className: 'fr-count' }, (index + 1) + ' / ' + __FR_STEPS.length)),
61
+ h('div', { className: 'fr-step' }, step.title),
62
+ h('div', { className: 'fr-body' }, step.body),
63
+ step.tryIt ? h('div', { className: 'fr-try' }, h('span', null, '可以直接说'), h('code', null, '「' + step.tryIt + '」')) : null,
64
+ h('div', { className: 'fr-bar' },
65
+ h('div', { className: 'fr-progress' }, __FR_STEPS.map((_, i) => h('span', { key: i, className: 'fr-seg' + (i <= index ? ' on' : '') }))),
66
+ h('button', { className: 'fr-btn ghost', type: 'button', onClick: close }, '跳过'),
67
+ index > 0 ? h('button', { className: 'fr-btn', type: 'button', onClick: () => setIndex(index - 1) }, '上一步') : null,
68
+ h('button', { className: 'fr-btn primary', type: 'button', onClick: () => { if (last) close(); else setIndex(index + 1); } }, last ? '开始使用' : '下一步')));
69
+ }
70
+ function __withFirstRun(Component) {
71
+ return function FirstRunWrapped(props) {
72
+ return h(React.Fragment, null, h(__FirstRunCard, null), h(Component, props));
73
+ };
74
+ }
75
+ // ---- end first-run guide ----
76
+
12
77
 
13
78
  // Harness supplies document.baseURI for reverse-proxy mounts and in-page navigation.
14
79
  const ROUTE = "_dsh/dsh-email/settings";
@@ -2857,9 +2922,10 @@ function apply(ctx) {
2857
2922
  return UI[lang]["nav.title"];
2858
2923
  },
2859
2924
  inject: () => ({}),
2860
- }, EmailSettingsSection));
2925
+ }, __withFirstRun(EmailSettingsSection)));
2861
2926
  }
2862
2927
 
2928
+ exports.__firstRunCard = __FirstRunCard;
2863
2929
  exports.apply = apply;
2864
2930
  exports.inject = inject;
2865
2931
 
package/lib/config.js CHANGED
@@ -415,7 +415,7 @@ function resolveAccount(name, common, acc, allowEnvPassword, providers, known) {
415
415
  problems.push(`账号 "${name}" 的${authUser === user ? '授权码 / 应用专用密码' : '登录账号的密码'}未填写`);
416
416
  }
417
417
  if (imap.host === undefined || imap.host === '')
418
- problems.push(`账号 "${name}" 的 imap.host 未填写(可填 provider 预设:${known.join('/')})`);
418
+ problems.push(`账号 "${name}" 的 imap.host 未填写(可填 provider 预设:${known.join(', ')})`);
419
419
  if (smtp.host === undefined || smtp.host === '')
420
420
  problems.push(`账号 "${name}" 的 smtp.host 未填写(同上)`);
421
421
  if (problems.length > 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-email",
3
- "version": "0.16.2",
3
+ "version": "0.17.0",
4
4
  "description": "在 DSH 中收发、搜索和整理邮件,支持多个邮箱账号。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",