@dsh-plus/notify-email 0.1.40 → 0.1.42
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/lib/client.js +81 -70
- package/lib/index.d.ts +1 -1
- package/lib/index.js +2 -2
- package/package.json +2 -2
- package/src/client/card.tsx +1 -1
- package/src/client/client.ts +2 -2
- package/src/config-api.ts +1 -1
- package/src/config.ts +4 -4
- package/src/ns.ts +1 -1
- package/src/service.ts +5 -5
package/lib/client.js
CHANGED
|
@@ -7,6 +7,77 @@ window.__ModuleLoader__.load({
|
|
|
7
7
|
let react_jsx_runtime = require("react/jsx-runtime");
|
|
8
8
|
let react = require("react");
|
|
9
9
|
require("@deepseek-ai/dsh-client-ui-primitives");
|
|
10
|
+
//#region ../shared/src/client/fields.tsx
|
|
11
|
+
/** 卡片按钮(与 CardChrome 页脚同一套类名与视觉)。 */
|
|
12
|
+
function Button(props) {
|
|
13
|
+
const p = props.prefix ?? "dshp";
|
|
14
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
15
|
+
type: "button",
|
|
16
|
+
className: `${p}-btn ${props.variant === "primary" ? `${p}-btnPrimary` : `${p}-btnGhost`}`,
|
|
17
|
+
disabled: props.disabled === true,
|
|
18
|
+
onClick: props.onClick,
|
|
19
|
+
children: props.label
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function TextField(props) {
|
|
23
|
+
const p = props.prefix ?? "dshp";
|
|
24
|
+
const invalid = props.invalid === true;
|
|
25
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
26
|
+
className: `${p}-field`,
|
|
27
|
+
children: [
|
|
28
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
29
|
+
className: `${p}-head`,
|
|
30
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
31
|
+
className: `${p}-label`,
|
|
32
|
+
htmlFor: props.id,
|
|
33
|
+
children: props.label
|
|
34
|
+
}), props.badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
35
|
+
className: `${p}-badge ${props.badge.set ? `${p}-badgeSet` : `${p}-badgeUnset`}`,
|
|
36
|
+
children: props.badge.text
|
|
37
|
+
}) : null]
|
|
38
|
+
}),
|
|
39
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
40
|
+
id: props.id,
|
|
41
|
+
className: `${p}-input${invalid ? ` ${p}-inputInvalid` : ""}`,
|
|
42
|
+
type: props.password === true ? "password" : "text",
|
|
43
|
+
inputMode: props.numeric === true ? "numeric" : void 0,
|
|
44
|
+
autoComplete: props.password === true ? "off" : void 0,
|
|
45
|
+
"aria-invalid": invalid || void 0,
|
|
46
|
+
value: props.value,
|
|
47
|
+
disabled: props.disabled === true,
|
|
48
|
+
onChange: (event) => props.onEdit(event.target.value)
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
51
|
+
className: invalid ? `${p}-invalid` : `${p}-hint`,
|
|
52
|
+
children: invalid ? props.invalidLabel ?? "" : props.hint ?? ""
|
|
53
|
+
})
|
|
54
|
+
]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 勾选行:自绘圆角扁平开关(switch),对齐官方 WebUI 无原生 checkbox 的
|
|
59
|
+
* 设计语言(官方选择类控件全走胶囊/菜单,见 cardCss 的 -switch 规则)。
|
|
60
|
+
* 语义保持 checkbox(无障碍树与表单语义不变),视觉自绘。
|
|
61
|
+
*/
|
|
62
|
+
function CheckRow(props) {
|
|
63
|
+
const p = props.prefix ?? "dshp";
|
|
64
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
65
|
+
className: `${p}-checkRow`,
|
|
66
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
67
|
+
id: props.id,
|
|
68
|
+
type: "checkbox",
|
|
69
|
+
role: "switch",
|
|
70
|
+
"aria-checked": props.checked,
|
|
71
|
+
checked: props.checked,
|
|
72
|
+
disabled: props.disabled === true,
|
|
73
|
+
onChange: (event) => props.onEdit(event.target.checked)
|
|
74
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
75
|
+
htmlFor: props.id,
|
|
76
|
+
children: props.label
|
|
77
|
+
})]
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
//#endregion
|
|
10
81
|
//#region ../shared/src/client/card.tsx
|
|
11
82
|
const IDLE_STATUS = {
|
|
12
83
|
kind: "idle",
|
|
@@ -55,12 +126,12 @@ window.__ModuleLoader__.load({
|
|
|
55
126
|
className: `${p}-status${props.status.kind === "error" ? ` ${p}-statusError` : ""}`,
|
|
56
127
|
role: "status",
|
|
57
128
|
children: props.status.text
|
|
58
|
-
}) : null, props.actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
129
|
+
}) : null, props.actions.map((action) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Button, {
|
|
130
|
+
prefix: p,
|
|
131
|
+
label: action.label,
|
|
132
|
+
variant: action.variant,
|
|
133
|
+
disabled: action.disabled,
|
|
134
|
+
onClick: action.onClick
|
|
64
135
|
}, action.key))]
|
|
65
136
|
})
|
|
66
137
|
]
|
|
@@ -115,66 +186,6 @@ window.__ModuleLoader__.load({
|
|
|
115
186
|
* @module @dsh-plus/shared/client/draft
|
|
116
187
|
*/
|
|
117
188
|
//#endregion
|
|
118
|
-
//#region ../shared/src/client/fields.tsx
|
|
119
|
-
function TextField(props) {
|
|
120
|
-
const p = props.prefix ?? "dshp";
|
|
121
|
-
const invalid = props.invalid === true;
|
|
122
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
123
|
-
className: `${p}-field`,
|
|
124
|
-
children: [
|
|
125
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
126
|
-
className: `${p}-head`,
|
|
127
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
128
|
-
className: `${p}-label`,
|
|
129
|
-
htmlFor: props.id,
|
|
130
|
-
children: props.label
|
|
131
|
-
}), props.badge !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
132
|
-
className: `${p}-badge ${props.badge.set ? `${p}-badgeSet` : `${p}-badgeUnset`}`,
|
|
133
|
-
children: props.badge.text
|
|
134
|
-
}) : null]
|
|
135
|
-
}),
|
|
136
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
137
|
-
id: props.id,
|
|
138
|
-
className: `${p}-input${invalid ? ` ${p}-inputInvalid` : ""}`,
|
|
139
|
-
type: props.password === true ? "password" : "text",
|
|
140
|
-
inputMode: props.numeric === true ? "numeric" : void 0,
|
|
141
|
-
autoComplete: props.password === true ? "off" : void 0,
|
|
142
|
-
"aria-invalid": invalid || void 0,
|
|
143
|
-
value: props.value,
|
|
144
|
-
disabled: props.disabled === true,
|
|
145
|
-
onChange: (event) => props.onEdit(event.target.value)
|
|
146
|
-
}),
|
|
147
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
148
|
-
className: invalid ? `${p}-invalid` : `${p}-hint`,
|
|
149
|
-
children: invalid ? props.invalidLabel ?? "" : props.hint ?? ""
|
|
150
|
-
})
|
|
151
|
-
]
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* 勾选行:自绘圆角扁平开关(switch),对齐官方 WebUI 无原生 checkbox 的
|
|
156
|
-
* 设计语言(官方选择类控件全走胶囊/菜单,见 cardCss 的 -switch 规则)。
|
|
157
|
-
* 语义保持 checkbox(无障碍树与表单语义不变),视觉自绘。
|
|
158
|
-
*/
|
|
159
|
-
function CheckRow(props) {
|
|
160
|
-
const p = props.prefix ?? "dshp";
|
|
161
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
162
|
-
className: `${p}-checkRow`,
|
|
163
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
164
|
-
id: props.id,
|
|
165
|
-
type: "checkbox",
|
|
166
|
-
role: "switch",
|
|
167
|
-
"aria-checked": props.checked,
|
|
168
|
-
checked: props.checked,
|
|
169
|
-
disabled: props.disabled === true,
|
|
170
|
-
onChange: (event) => props.onEdit(event.target.checked)
|
|
171
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
172
|
-
htmlFor: props.id,
|
|
173
|
-
children: props.label
|
|
174
|
-
})]
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
//#endregion
|
|
178
189
|
//#region ../shared/src/client/i18n.ts
|
|
179
190
|
/** 卡片通用文案(save/discard/unsaved/loading 等四插件共有键)。 */
|
|
180
191
|
const commonZh = {
|
|
@@ -184,7 +195,7 @@ window.__ModuleLoader__.load({
|
|
|
184
195
|
unsaved: "未保存",
|
|
185
196
|
loading: "加载中…",
|
|
186
197
|
unavailable: "配置服务不可用。",
|
|
187
|
-
readOnly: "当前部署无 settings provider
|
|
198
|
+
readOnly: "当前部署无 settings provider,配置为只读;请在 profile 的 cordis.patch.yml 行级配置。",
|
|
188
199
|
invalidNumber: "请输入正整数。",
|
|
189
200
|
collapse: "收起",
|
|
190
201
|
expand: "展开",
|
|
@@ -201,7 +212,7 @@ window.__ModuleLoader__.load({
|
|
|
201
212
|
unsaved: "Unsaved",
|
|
202
213
|
loading: "Loading…",
|
|
203
214
|
unavailable: "Settings service unavailable.",
|
|
204
|
-
readOnly: "No settings provider in this deployment; config is read-only.
|
|
215
|
+
readOnly: "No settings provider in this deployment; config is read-only. Configure it at the profile row in cordis.patch.yml.",
|
|
205
216
|
invalidNumber: "Enter a positive integer.",
|
|
206
217
|
collapse: "Collapse",
|
|
207
218
|
expand: "Expand",
|
|
@@ -408,7 +419,7 @@ ${extra}
|
|
|
408
419
|
//#region src/ns.ts
|
|
409
420
|
/**
|
|
410
421
|
* settings 命名空间字面量(纯常量,零依赖,浏览器半可安全引入)。
|
|
411
|
-
* 服务端直接以字面量注册(
|
|
422
|
+
* 服务端直接以字面量注册(dsh-settings 对命名空间做编译期
|
|
412
423
|
* 语法校验,见 config.ts);浏览器半把它作为配置卡片的注册键
|
|
413
424
|
* (插件页配置卡片挂在 row/bundle config 槽位上,与命名空间解耦,
|
|
414
425
|
* 见 shared/config-slots),
|
|
@@ -619,7 +630,7 @@ ${extra}
|
|
|
619
630
|
* 外壳与基础控件走 @dsh-plus/shared/client 套件(CardChrome/TextField/CheckRow),
|
|
620
631
|
* 本文件只保留业务字段与保存/测试逻辑。交互对齐官方卡片:折叠/展开、
|
|
621
632
|
* staged draft、未保存标记、保存/放弃;另加「发送测试邮件」。
|
|
622
|
-
* 配置读写经 ctx.remote.settings 直连(
|
|
633
|
+
* 配置读写经 ctx.remote.settings 直连(connection.api.settings
|
|
623
634
|
* 已移除):value 为 schema 解析后的脱敏视图
|
|
624
635
|
* (smtp.pass 不出现,passConfigured 由 describe 的 secrets 探测),
|
|
625
636
|
* 保存经 settings.update 深合并(空 pass 剔除 = 保持不变)。
|
package/lib/index.d.ts
CHANGED
|
@@ -71,7 +71,7 @@ declare const Config: z<Schemastery.ObjectS<NoInfer<{
|
|
|
71
71
|
maxBodyChars: z<number, number, "volatile-defined">;
|
|
72
72
|
dryRun: z<boolean, boolean, "volatile-defined">;
|
|
73
73
|
}>>, "plain">;
|
|
74
|
-
/** 活动字段形态(
|
|
74
|
+
/** 活动字段形态(loader 解析产物:volatile 字段为活动引用)。 */
|
|
75
75
|
type NotifyEmailConfigFields = Schemastery.TypeT<typeof Config>;
|
|
76
76
|
/** 平面配置形态(消费面的读取形态,由活动引用解包得到)。 */
|
|
77
77
|
type NotifyEmailConfig = UnwrapVolatile<NotifyEmailConfigFields>;
|
package/lib/index.js
CHANGED
|
@@ -74,9 +74,9 @@ function registerTestApi(ctx, service) {
|
|
|
74
74
|
//#region src/config.ts
|
|
75
75
|
/**
|
|
76
76
|
* 配置单一事实源:cordis 行级 Config(组合默认值,dev/prod patch 层可覆盖)
|
|
77
|
-
* 与 settings namespace
|
|
77
|
+
* 与 settings namespace(用户层=profile 行级覆盖层 cordis.patch.yml)
|
|
78
78
|
* 共用同一 schemastery schema。SMTP 密码走官方 credentials seam
|
|
79
|
-
* (refs/NOTIFY_EMAIL_SMTP_PASS),不进 settings
|
|
79
|
+
* (refs/NOTIFY_EMAIL_SMTP_PASS),不进 settings 用户层(存储规范)。
|
|
80
80
|
* @module notify-email/config
|
|
81
81
|
*/
|
|
82
82
|
/** SMTP 密码在官方 credentials seam 中的引用名。 */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dsh-plus/notify-email",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"description": "dsh-plus service+ui plugin: 任务结束/等待决策/出错时向指定邮箱发送邮件通知",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"nodemailer": "9.0.6",
|
|
35
|
-
"@dsh-plus/shared": "0.1.
|
|
35
|
+
"@dsh-plus/shared": "0.1.36"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
38
|
"@deepseek-ai/cordis": "^4.0.5-alpha.1",
|
package/src/client/card.tsx
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* 外壳与基础控件走 @dsh-plus/shared/client 套件(CardChrome/TextField/CheckRow),
|
|
5
5
|
* 本文件只保留业务字段与保存/测试逻辑。交互对齐官方卡片:折叠/展开、
|
|
6
6
|
* staged draft、未保存标记、保存/放弃;另加「发送测试邮件」。
|
|
7
|
-
* 配置读写经 ctx.remote.settings 直连(
|
|
7
|
+
* 配置读写经 ctx.remote.settings 直连(connection.api.settings
|
|
8
8
|
* 已移除):value 为 schema 解析后的脱敏视图
|
|
9
9
|
* (smtp.pass 不出现,passConfigured 由 describe 的 secrets 探测),
|
|
10
10
|
* 保存经 settings.update 深合并(空 pass 剔除 = 保持不变)。
|
package/src/client/client.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* 类型说明:浏览器半只用到 slots/locale/remote 的很窄一面,
|
|
9
9
|
* scope 与基础控件走 @dsh-plus/shared/client 套件(收编自本插件原实现)。
|
|
10
|
-
* 配置读写经 ctx.remote.settings 直连(
|
|
11
|
-
* 已移除;
|
|
10
|
+
* 配置读写经 ctx.remote.settings 直连(connection.api.settings
|
|
11
|
+
* 已移除; settingsScope 服务亦删除(configForms 取代)——插件卡片自始
|
|
12
12
|
* 直连 remote.settings);自定义端点仅剩「发送测试邮件」(api.ts)。
|
|
13
13
|
* 卡片 key/rowId 约定见 @dsh-plus/shared/client/config-slots。
|
|
14
14
|
* @module @dsh-plus/notify-email/client
|
package/src/config-api.ts
CHANGED
package/src/config.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 配置单一事实源:cordis 行级 Config(组合默认值,dev/prod patch 层可覆盖)
|
|
3
|
-
* 与 settings namespace
|
|
3
|
+
* 与 settings namespace(用户层=profile 行级覆盖层 cordis.patch.yml)
|
|
4
4
|
* 共用同一 schemastery schema。SMTP 密码走官方 credentials seam
|
|
5
|
-
* (refs/NOTIFY_EMAIL_SMTP_PASS),不进 settings
|
|
5
|
+
* (refs/NOTIFY_EMAIL_SMTP_PASS),不进 settings 用户层(存储规范)。
|
|
6
6
|
* @module notify-email/config
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -11,7 +11,7 @@ import type { UnwrapVolatile } from '@dsh-plus/shared'
|
|
|
11
11
|
|
|
12
12
|
import { SETTINGS_NS as NS_LITERAL } from './ns.ts'
|
|
13
13
|
|
|
14
|
-
/** settings
|
|
14
|
+
/** settings 命名空间(字面量即合法命名空间,编译期校验;webui 配置卡片与插件运行期读取同一份)。 */
|
|
15
15
|
export const SETTINGS_NS = NS_LITERAL
|
|
16
16
|
|
|
17
17
|
/** SMTP 密码在官方 credentials seam 中的引用名。 */
|
|
@@ -65,7 +65,7 @@ export const Config = z.object({
|
|
|
65
65
|
dryRun: z.boolean().description('仅记录日志不真实发送(开发调试用)').default(false).volatile(),
|
|
66
66
|
})
|
|
67
67
|
|
|
68
|
-
/** 活动字段形态(
|
|
68
|
+
/** 活动字段形态(loader 解析产物:volatile 字段为活动引用)。 */
|
|
69
69
|
export type NotifyEmailConfigFields = Schemastery.TypeT<typeof Config>
|
|
70
70
|
/** 平面配置形态(消费面的读取形态,由活动引用解包得到)。 */
|
|
71
71
|
export type NotifyEmailConfig = UnwrapVolatile<NotifyEmailConfigFields>
|
package/src/ns.ts
CHANGED
package/src/service.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* NotifyEmailService:通知编排中枢。
|
|
3
|
-
* - 配置:
|
|
3
|
+
* - 配置:volatile 活动引用(loader 解析层并入用户层,GUI 写入原位提交
|
|
4
4
|
* 热生效),无 settings provider 时即 cordis 行级 config 本身;
|
|
5
5
|
* - 触发器:registerTrigger 是第三方插件的扩展接口;内置官方适配器同路径注册。
|
|
6
6
|
* - 投递:首个非空 EmailNotice 经 Mailer 发送;单个触发器抛错不影响其余。
|
|
@@ -32,9 +32,9 @@ function credentialsOf(ctx: Context): CredentialsSeamLike {
|
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export class NotifyEmailService extends Service {
|
|
35
|
-
// cordis
|
|
36
|
-
//
|
|
37
|
-
//
|
|
35
|
+
// cordis 以普通静态属性读取插件级 inject(Context.inject 符号不存在,
|
|
36
|
+
// computed key 会静默变成字符串 'undefined' 使声明失效——曾因此出过回归:
|
|
37
|
+
// credentials 未就绪时构造读 ctx.credentials 抛
|
|
38
38
|
// "cannot get property credentials without inject",服务 fiber 静默 FAILED)。
|
|
39
39
|
static inject = ['agents', 'tools', 'credentials']
|
|
40
40
|
|
|
@@ -44,7 +44,7 @@ export class NotifyEmailService extends Service {
|
|
|
44
44
|
|
|
45
45
|
constructor(ctx: Context, config: NotifyEmailConfig | NotifyEmailConfigFields) {
|
|
46
46
|
super(ctx, 'notifyEmail')
|
|
47
|
-
//
|
|
47
|
+
// 替代已删除的 installSection/setSource:活动引用原位提交,现取即热。
|
|
48
48
|
this.current = () => unwrapVolatile(config)
|
|
49
49
|
const logger = ctx.logger('notify-email')
|
|
50
50
|
const audit = createJsonlAuditSink(pluginDataPath('notify-email', 'audit.jsonl'), (message) =>
|