feat(mail): 具名化 JS 导出并动态包裹错误(by AI)

This commit is contained in:
AI Engineer 2026-06-21 10:31:21 +08:00
parent 3173092d4f
commit 3d5f3ba909
4 changed files with 75 additions and 35 deletions

View File

@ -1,5 +1,9 @@
# CHANGELOG
## v1.5.3 (2026-06-21)
- **JS 对齐**: 重构 JS 导出为具名函数,并引入 `jsmod.MakeError` 动态包装错误以获取调用栈。
- **依赖更新**: 升级依赖 `jsmod``v1.5.3``cast``v1.5.3``rand``v1.5.3``encoding``v1.5.4``shell``v1.5.3``safe``v1.5.2``id``v1.5.4``file``v1.5.5``config``v1.5.3``log``v1.5.8`
## v1.0.4 (2026-05-31)
- **新增**: 注册到 `jsmod`。支持低代码环境下的邮件发送与接收。
- 提供 `send`, `recv` 默认快捷操作。

View File

@ -18,5 +18,6 @@
| 内存占用 | 低 | 采用流式处理及即时擦除 |
## 验证结果
- **单元测试**: `go test -v ./...` 通过。
- **单元测试**: `go test -v ./...` 通过 (2026-06-21)
- **并发安全性**: 经过 `sync.RWMutex` 保护,支持多协程下注册 Handler 及发送。
- **JS 错误调用栈**: JS 桥接层改用具名导出并使用 `jsmod.MakeError` 包裹错误,确保 JS 抛出异常时携带准确的 Go 运行时堆栈。

20
go.mod
View File

@ -3,11 +3,11 @@ module apigo.cc/go/mail
go 1.26.1
require (
apigo.cc/go/cast v1.5.2
apigo.cc/go/file v1.5.4
apigo.cc/go/jsmod v1.5.2
apigo.cc/go/log v1.5.6
apigo.cc/go/safe v1.5.1
apigo.cc/go/cast v1.5.3
apigo.cc/go/file v1.5.5
apigo.cc/go/jsmod v1.5.3
apigo.cc/go/log v1.5.8
apigo.cc/go/safe v1.5.2
github.com/emersion/go-imap/v2 v2.0.0-beta.8
github.com/jaytaylor/html2text v0.0.0-20260303211410-1a4bdc82ecec
github.com/jhillyerd/enmime v1.3.0
@ -15,11 +15,11 @@ require (
)
require (
apigo.cc/go/config v1.5.2 // indirect
apigo.cc/go/encoding v1.5.3 // indirect
apigo.cc/go/id v1.5.3 // indirect
apigo.cc/go/rand v1.5.2 // indirect
apigo.cc/go/shell v1.5.2 // indirect
apigo.cc/go/config v1.5.3 // indirect
apigo.cc/go/encoding v1.5.4 // indirect
apigo.cc/go/id v1.5.4 // indirect
apigo.cc/go/rand v1.5.3 // indirect
apigo.cc/go/shell v1.5.3 // indirect
github.com/cention-sany/utf7 v0.0.0-20170124080048-26cad61bd60a // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/clipperhouse/displaywidth v0.10.0 // indirect

View File

@ -8,34 +8,59 @@ import (
func init() {
jsmod.Register("mail", map[string]any{
// 默认邮箱操作 (对齐 PascalCase)
"Send": func(to any, subject, content string, option *SendOption) error {
var toList []string
cast.Convert(&toList, to)
return Send(toList, subject, content, option)
},
"Recv": func(opt *RecvOption) (*RecvResult, error) {
return Recv(opt)
},
"Send": jsSend,
"Recv": jsRecv,
// 多实例获取 (对齐 PascalCase支持可选参数)
"Mailbox": func(name *string) *jsMailbox {
target := "default"
if name != nil {
target = *name
}
m := GetMailbox(target)
if m == nil {
return nil
}
return &jsMailbox{m: m}
},
"Mailbox": jsMailboxGetter,
// 辅助工具
"FormatAddr": FormatAddr,
"ParseAddr": ParseAddr,
"FormatAddr": jsFormatAddr,
"ParseAddr": jsParseAddr,
})
}
func jsSend(to any, subject, content string, option *SendOption) error {
var toList []string
cast.Convert(&toList, to)
if err := Send(toList, subject, content, option); err != nil {
return jsmod.MakeError(err)
}
return nil
}
func jsRecv(opt *RecvOption) (*RecvResult, error) {
res, err := Recv(opt)
if err != nil {
return nil, jsmod.MakeError(err)
}
return res, nil
}
func jsMailboxGetter(name *string) *jsMailbox {
target := "default"
if name != nil {
target = *name
}
m := GetMailbox(target)
if m == nil {
return nil
}
return &jsMailbox{m: m}
}
func jsFormatAddr(name, address string) string {
return FormatAddr(name, address)
}
func jsParseAddr(addr string) (string, string, error) {
name, address, err := ParseAddr(addr)
if err != nil {
return "", "", jsmod.MakeError(err)
}
return name, address, nil
}
// jsMailbox 包装 Mailbox 实例
type jsMailbox struct {
m *Mailbox
@ -44,13 +69,23 @@ type jsMailbox struct {
func (j *jsMailbox) Send(to any, subject, content string, option *SendOption) error {
var toList []string
cast.Convert(&toList, to)
return j.m.Send(toList, subject, content, option)
if err := j.m.Send(toList, subject, content, option); err != nil {
return jsmod.MakeError(err)
}
return nil
}
func (j *jsMailbox) Recv(opt *RecvOption) (*RecvResult, error) {
return j.m.Recv(opt)
res, err := j.m.Recv(opt)
if err != nil {
return nil, jsmod.MakeError(err)
}
return res, nil
}
func (j *jsMailbox) Health() error {
return j.m.Health()
if err := j.m.Health(); err != nil {
return jsmod.MakeError(err)
}
return nil
}