@agentunion/fastaun 0.5.33 → 0.5.35

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.
Files changed (113) hide show
  1. package/CHANGELOG.md +59 -2
  2. package/README.md +28 -26
  3. package/_packed_docs/CHANGELOG.md +59 -2
  4. package/_packed_docs/INDEX.md +26 -12
  5. package/_packed_docs/KITE_DOCS_GUIDE.md +17 -11
  6. package/_packed_docs/agent.md/SCHEMA.md +1 -1
  7. package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +2 -2
  8. package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +58 -8
  9. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +17 -17
  10. package/_packed_docs/protocol/echo-probe-gateway.md +99 -0
  11. package/_packed_docs/protocol/echo-probe-sdk.md +91 -0
  12. package/_packed_docs/sdk/0.5.33-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +464 -316
  13. package/_packed_docs/sdk/0.5.33-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +499 -304
  14. package/_packed_docs/sdk/0.5.34-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +133 -0
  15. package/_packed_docs/sdk/0.5.34-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +107 -0
  16. package/_packed_docs/sdk/0.5.35-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +189 -0
  17. package/_packed_docs/sdk/0.5.35-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +204 -0
  18. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +16 -13
  19. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +13 -1
  20. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +19 -9
  21. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +87 -20
  22. package/_packed_docs/sdk/09-collab-rpc-manual.md +48 -30
  23. package/_packed_docs/sdk/09-custody-api-manual.md +3 -3
  24. package/_packed_docs/sdk/09-group-rpc-manual.md +60 -13
  25. package/_packed_docs/sdk/09-message-rpc-manual.md +22 -0
  26. package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -1
  27. package/_packed_docs/sdk/09-payload-reference.md +9 -8
  28. package/_packed_docs/sdk/09-proxy-rpc-manual.md +20 -14
  29. package/_packed_docs/sdk/09-storage-rpc-manual.md +1698 -1659
  30. package/_packed_docs/sdk/09-stream-rpc-manual.md +33 -20
  31. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +19 -17
  32. package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +125 -30
  33. package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/274/200/345/217/221/347/247/273/346/244/215/346/214/207/345/215/227.md +109 -33
  34. package/_packed_docs/sdk/INDEX.md +30 -18
  35. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +1 -1
  36. package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +5 -5
  37. package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +5 -5
  38. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +9 -9
  39. package/_packed_docs/sdk/README.md +11 -6
  40. package/_packed_docs//346/266/210/346/201/257/345/274/271/346/200/247/350/241/245/346/213/211/351/200/232/351/201/223/345/256/236/346/226/275/350/256/241/345/210/222.md +400 -0
  41. package/_packed_docs//346/266/210/346/201/257/345/274/271/346/200/247/350/241/245/346/213/211/351/200/232/351/201/223/346/226/271/346/241/210.md +485 -0
  42. package/dist/auth.js +39 -45
  43. package/dist/auth.js.map +1 -1
  44. package/dist/client/control-messages.js +2 -2
  45. package/dist/client/control-messages.js.map +1 -1
  46. package/dist/client/delivery.d.ts +12 -1
  47. package/dist/client/delivery.js +281 -46
  48. package/dist/client/delivery.js.map +1 -1
  49. package/dist/client/lifecycle.js +13 -1
  50. package/dist/client/lifecycle.js.map +1 -1
  51. package/dist/client/rpc-budget.d.ts +21 -0
  52. package/dist/client/rpc-budget.js +82 -0
  53. package/dist/client/rpc-budget.js.map +1 -0
  54. package/dist/client/rpc-pipeline.d.ts +5 -0
  55. package/dist/client/rpc-pipeline.js +227 -63
  56. package/dist/client/rpc-pipeline.js.map +1 -1
  57. package/dist/client/sync-channels.d.ts +90 -0
  58. package/dist/client/sync-channels.js +508 -0
  59. package/dist/client/sync-channels.js.map +1 -0
  60. package/dist/client/v2-e2ee.d.ts +5 -1
  61. package/dist/client/v2-e2ee.js +420 -303
  62. package/dist/client/v2-e2ee.js.map +1 -1
  63. package/dist/client.d.ts +17 -0
  64. package/dist/client.js +373 -50
  65. package/dist/client.js.map +1 -1
  66. package/dist/events.d.ts +1 -0
  67. package/dist/events.js +5 -0
  68. package/dist/events.js.map +1 -1
  69. package/dist/index.d.ts +3 -1
  70. package/dist/index.js +1 -0
  71. package/dist/index.js.map +1 -1
  72. package/dist/mail-client.d.ts +101 -0
  73. package/dist/mail-client.js +369 -0
  74. package/dist/mail-client.js.map +1 -0
  75. package/dist/pubsub/binding.js +23 -3
  76. package/dist/pubsub/binding.js.map +1 -1
  77. package/dist/pubsub/channel.d.ts +15 -3
  78. package/dist/pubsub/channel.js +114 -7
  79. package/dist/pubsub/channel.js.map +1 -1
  80. package/dist/pubsub/client.d.ts +17 -2
  81. package/dist/pubsub/client.js +205 -40
  82. package/dist/pubsub/client.js.map +1 -1
  83. package/dist/pubsub/credentials.d.ts +3 -0
  84. package/dist/pubsub/credentials.js +57 -20
  85. package/dist/pubsub/credentials.js.map +1 -1
  86. package/dist/pubsub/index.d.ts +5 -2
  87. package/dist/pubsub/index.js +70 -54
  88. package/dist/pubsub/index.js.map +1 -1
  89. package/dist/pubsub/service.d.ts +9 -0
  90. package/dist/pubsub/service.js +266 -20
  91. package/dist/pubsub/service.js.map +1 -1
  92. package/dist/pubsub/types.d.ts +13 -1
  93. package/dist/storage/lowlevel.d.ts +3 -1
  94. package/dist/storage/lowlevel.js +13 -0
  95. package/dist/storage/lowlevel.js.map +1 -1
  96. package/dist/storage/types.d.ts +10 -0
  97. package/dist/storage/types.js.map +1 -1
  98. package/dist/storage/vfs.d.ts +3 -1
  99. package/dist/storage/vfs.js +2 -2
  100. package/dist/storage/vfs.js.map +1 -1
  101. package/dist/tools/cross-sdk-agent.d.ts +55 -5
  102. package/dist/tools/cross-sdk-agent.js +88 -21
  103. package/dist/tools/cross-sdk-agent.js.map +1 -1
  104. package/dist/transport.d.ts +16 -0
  105. package/dist/transport.js +129 -7
  106. package/dist/transport.js.map +1 -1
  107. package/dist/udp-standby.d.ts +89 -0
  108. package/dist/udp-standby.js +487 -0
  109. package/dist/udp-standby.js.map +1 -0
  110. package/dist/version.d.ts +1 -1
  111. package/dist/version.js +1 -1
  112. package/package.json +5 -1
  113. package/scripts/patch-imapflow-external.mjs +69 -0
@@ -0,0 +1,204 @@
1
+ # 0.5.35 SDK 开发与移植指南
2
+
3
+ 本文面向维护四 SDK、实现新语言 SDK 或核对兼容性的开发者,整理已发布 **0.5.34 → 目标 0.5.35** 的协议、状态机与实现增量,依据截至 2026-11-12 的工作区源码。
4
+
5
+ 应用调用和升级验收见 [应用集成指南](0.5.35-SDK应用集成指南.md),比较基线、四端落点和已有验证见 [parity 0.5.35](../../python/CHANGES_FOR_PARITY.md#v0535)。既有身份、E2EE、EventService durable outbox、Storage、Group FS 与 Service Proxy 契约继续参考 [0.5.34 开发与移植指南](0.5.34-SDK开发与移植指南.md),本文只展开本版增量。
6
+
7
+ ## 1. 实现范围与职责
8
+
9
+ | 范围 | Python | Node TypeScript | Browser JavaScript | Go |
10
+ | --- | --- | --- | --- | --- |
11
+ | EventService 模式、过滤、本地通道 | 支持;SQLite | 支持;SQLite | 支持;IndexedDB | 支持;SQLite |
12
+ | 累计 ACK、同步恢复、Echo v3.2 | 支持 | 支持 | 支持 | 支持 |
13
+ | UDP 待机 | 原生 UDP | 原生 UDP | 无原生实现 | 原生 UDP |
14
+ | 独立 MailClient | SMTP/IMAP | SMTP/IMAP | 无原生实现 | SMTP/IMAP |
15
+
16
+ SDK 负责本地状态、认证请求、投递调度和连接生命周期;Gateway/Message/Group/独立 Mail 服务负责对应服务端事实。本版配套服务按**单实例部署**支持,Redis 缓存不构成多实例一致性契约。移植时不能把 SDK 的进程内能力扩写为服务多副本承诺,也不能将 Mail 客户端实现视为邮件服务整体已验收。
17
+
18
+ ## 2. EventService 订阅契约
19
+
20
+ ### 2.1 模式先展开,再保存具体事件
21
+
22
+ `subscribe`/`unsubscribe` 的事件模式按 `.` 分层,层内 `*` 不跨点;拒绝空层和 `**`,不执行正则。授权申请、grant scope、publish 保持完整事件名。订阅执行顺序为:
23
+
24
+ 1. 校验过滤参数,检查当前 AID/device/slot 的有效租约。
25
+ 2. 逐模式在当前 Bus 目录展开,无命中返回 `UNKNOWN_EVENT`;与 Sub 授权求交,无可订阅事件返回 `FORBIDDEN`。
26
+ 3. 按具体事件替换订阅条件并持久化。
27
+ 4. 返回实际具体事件;以后新增目录项不会自动加入既有订阅。
28
+
29
+ 取消订阅的模式在当前订阅集合中匹配,不能按模式扩大或恢复租约授权。
30
+
31
+ ### 2.2 过滤 wire 与信任来源
32
+
33
+ | wire/Python | TS/JS | Go |
34
+ | --- | --- | --- |
35
+ | `publisher_aids` | `publisherAids` | `PublisherAIDs` |
36
+ | `publisher_types` | `publisherTypes` | `PublisherTypes` |
37
+ | `publisher_exttypes` | `publisherExttypes` | `PublisherExtTypes` |
38
+
39
+ 每字段为非空数组,1–64 项,每模式 UTF-8 最多 256 字节;省略不限。同字段 OR、跨字段 AND,沿用点分层通配。再次订阅同事件时替换过滤,不能把新条件与旧条件暗中合并。
40
+
41
+ 发布者 AID 取认证发送者;类型取验签通过的 `agent.md`,不信事件正文自报。仅在订阅要求类型时解析名片,缓存与并发均有界;读取或验签失败时,不匹配要求该类型的条件,不应连带拒绝仅 AID 或不限类型的订阅。
42
+
43
+ ### 2.3 持久化与订阅代次
44
+
45
+ Bus 端和客户端保存具体事件及完整过滤,重授权后逐事件恢复。状态应保持 AID、Bus、角色、device、slot 的既有隔离;Python/Node/Go 的 SQLite 与 Browser 的 IndexedDB 只改变存储介质,不改变过滤语义。
46
+
47
+ 修改条件、取消订阅或关闭会改变订阅代次。接收排队与开始回调前复核代次,旧代次事件不能继续按旧条件进入回调;不能据此保证回滚已执行的业务。
48
+
49
+ ### 2.4 同 Client 本地通道
50
+
51
+ 只有同一个 Client、Bus AID 为本端且 device/slot 匹配时允许本地收发;跨 Client/设备/slot 保持网络路径。投递复制消息后进入原接收处理,不能直接调用业务回调跳过授权与调度。
52
+
53
+ 本地路径保留角色授权、注册租约、TTL、去重、容量和关闭代际。容量满时等待容量或原期限,不建立无限队列;本地投递不重复扣网络接收速率。
54
+
55
+ | SDK | 主要落点 |
56
+ | --- | --- |
57
+ | Python | [pubsub/client.py](../../python/src/aun_core/pubsub/client.py)、[service.py](../../python/src/aun_core/pubsub/service.py)、[binding.py](../../python/src/aun_core/pubsub/binding.py) |
58
+ | Node TS | [pubsub/types.ts](../../ts/src/pubsub/types.ts)、[client.ts](../../ts/src/pubsub/client.ts)、[service.ts](../../ts/src/pubsub/service.ts)、[channel.ts](../../ts/src/pubsub/channel.ts) |
59
+ | Browser JS | [pubsub/client.ts](../../js/src/pubsub/client.ts)、[service.ts](../../js/src/pubsub/service.ts)、[channel.ts](../../js/src/pubsub/channel.ts) |
60
+ | Go | [pubsub_types.go](../../go/pubsub_types.go)、[pubsub_client.go](../../go/pubsub_client.go)、[pubsub_service.go](../../go/pubsub_service.go)、[pubsub_binding.go](../../go/pubsub_binding.go) |
61
+
62
+ 完整事件租约、凭证、fanout 和公平背压继续遵循 [事件开发移植专题](AUN事件发布订阅开发移植指南.md)。
63
+
64
+ ## 3. ACK、同步预算与恢复调度
65
+
66
+ ### 3.1 累计 ACK 的提交与收尾
67
+
68
+ 后台 Pull 在本地提交后异步调度累计 ACK。同 namespace 合并更高确认水位,失败重试;前台 Pull 保持等待 ACK。任务按 AID、device、slot、连接与 namespace 代际隔离,旧任务不能确认新会话的数据。
69
+
70
+ TS/JS 合并任务时同步更新待发送参数。任务成功结束前先移除当前 ACK job,使随后更高水位可创建新任务;最终清理须检查任务身份,不能把同 key 下的新 job 一并删除。
71
+
72
+ 关闭仅有限等待后台 ACK。协议确认不表示业务完成,重连重复投递和应用幂等仍遵循既有消息契约。
73
+
74
+ ### 3.2 历史同步与连接需求
75
+
76
+ 移除 `history_bytes_per_second` 主动字节速率节流,保留并发、`max_page_bytes`、在途内存预留和压力背压;volatile 继续独立游标,不与持久消息历史进度混用。TS/JS 避免重复补拉已被在线交付覆盖的范围,并合并群补拉责任。
77
+
78
+ 辅助连接 ready/退役后按实际可用连接重新发布同步需求。`gateway.sync_demand` 属于同步控制通知,不增加业务活动或因此阻止 UDP 空闲待机。
79
+
80
+ 自动连接后的补拉、组织身份和待上传名片恢复随机延后 30–60 秒。执行前复核身份和连接代际,关闭后台同步时不调度;显式 Pull 与消息通知仍由各自入口触发,不能将所有入口统一加延时。
81
+
82
+ 落点:Python [delivery.py](../../python/src/aun_core/_client/delivery.py)、[sync_channels.py](../../python/src/aun_core/_client/sync_channels.py)、[client.py](../../python/src/aun_core/client.py);TS/JS 各自 `src/client/{delivery,sync-channels,v2-e2ee,lifecycle}.ts`;Go [client_delivery.go](../../go/client_delivery.go)、[sync_channels.go](../../go/sync_channels.go)、[client_lifecycle.go](../../go/client_lifecycle.go)、[org_facades.go](../../go/org_facades.go)。
83
+
84
+ ## 4. Echo v3.2 处理契约
85
+
86
+ 完整 wire 以 [Echo SDK 规范](../protocol/echo-probe-sdk.md)为准。四端移植应保持以下行为:
87
+
88
+ | 环节 | 契约 |
89
+ | --- | --- |
90
+ | 识别 | 首行去前导空白,大小写不敏感,最长前缀顺序为 `echo.ecdiag`、`echo.ask`、`echo` |
91
+ | 传输 | 强制明文;认证错误和密文发送不转换成本地发送失败诊断 |
92
+ | hop | 唯一字段,默认 100;payload 有效安全整数优先于首行 `hop=N`;范围 ±9007199254740991 |
93
+ | 转向 | 去程递减到 0 立即返程,负数是回程并继续减;旧 `max_hop`/`rhop` 不控制状态 |
94
+ | trace | 保留完整正文和重复节点,携带版本、epoch、时区等;回程耗时取本地单调时钟 |
95
+ | 交付 | 本地提前返回和服务端 `echo_return` 复用 `message.received`/`group.message_created`;群提前返回定向原发送者 |
96
+ | 错误 | 本地发送失败/超时带 `reason=send_failed\|timeout`、`delivery_state=not_delivered\|unknown`、`echo_error` |
97
+
98
+ `unknown` 不能缩减为确定未投递。交付队列关闭后不为诊断重新打开,回调失败不能再次生成同一诊断;不能把四 SDK 的实现核对扩写为外部 App/Rust/EvolCore 全链路已通过。
99
+
100
+ ## 5. UDP 待机状态机与报文
101
+
102
+ ### 5.1 协商、prepare 与恢复
103
+
104
+ 能力只用于 Python/Node TS/Go 的主长连接,必须同时严格匹配两个布尔值:`negotiated_capabilities.udp_standby_v1=true` 与 `udp_standby.enabled=true`。缺省关闭或未协商则保持 WS;辅助连接和短连接不声明此能力。
105
+
106
+ 状态顺序为 active → preparing → UDP 验证 → commit → standby → waking → active。human 名片、未完成 RPC/ACK/同步/交付、迁移与关闭会阻止或中断入睡;不能使用注册意图替代当前名片类型判断。
107
+
108
+ prepare 返回的 `event_subscriptions` 必须保存为快照;恢复时写回 `auth.connect.options.event_subscriptions`。这是 Gateway 协议通知订阅,区别于 EventService 的 Bus 订阅。默认全事件、queue/stream 及非白名单订阅保持 WS,SDK 不擅自改变应用订阅。
109
+
110
+ 业务请求和 UDP 提示可合并触发恢复,但各请求的 deadline/cancel 独立。ticket/lease/对账期限和心跳连续失败也触发恢复;关闭和身份代际切换应终止旧等待,已经发出的写请求不自动重放。
111
+
112
+ ### 5.2 认证与心跳格式
113
+
114
+ UDP 报文使用 HMAC-SHA256,`c2s`/`s2c` 方向域分离;使用 64 位序号和 64 位窗口防重放,总包长最多 256 字节。UDP 只传控制信息;WAKE_ACK 不代表业务消费,也不改变消息 TTL。
115
+
116
+ `HEARTBEAT_ACK` 正文固定 **20 字节**,多字节整数使用网络字节序:
117
+
118
+ | 偏移 | 字段 | 类型 |
119
+ | --- | --- | --- |
120
+ | 0 | `lease_remaining_ms` | uint32 |
121
+ | 4 | `pending_generation` | uint64 |
122
+ | 12 | `reason_mask` | uint32 |
123
+ | 16 | `heartbeat_interval_ms` | uint32 |
124
+
125
+ 只接受当前 ticket/epoch、通过认证与重放检查、匹配当前未完成心跳且在期限内的 ACK。新周期决定下一轮调度并保留 ±20% 抖动;成功应重置连续失败计数,pending/reason 触发唤醒。默认策略约为 25 秒周期、5 秒等待、连续三次失败回 WS,实际以协商策略及租约/ticket/对账期限为准。
126
+
127
+ | SDK | 当前新周期处理与实现 |
128
+ | --- | --- |
129
+ | Python | [_receive](../../python/src/aun_core/_client/udp_standby.py) 在通过认证和请求匹配后更新 policy,心跳循环下一轮读取 |
130
+ | Node TS | [udp-standby.ts](../../ts/src/udp-standby.ts) 读取偏移 16,更新 policy 并重新安排 timer |
131
+ | Go | [udp_standby.go](../../go/udp_standby.go) 更新本轮策略并计算下一次心跳时间 |
132
+
133
+ 验证应通过实际收包入口进入循环,不能仅用绕过收包处理的 `_exchange` mock 判断周期更新。Python 现有回归覆盖当前/过期/已完成/已取消 ACK、零周期、下一轮新周期及抖动、成功后重新累计三次超时。
134
+
135
+ 编解码落点:Python [udp_standby_codec.py](../../python/src/aun_core/_client/udp_standby_codec.py)、Go [udp_standby_codec.go](../../go/udp_standby_codec.go);设计背景见 [AID 空闲 UDP 待机详细设计](../../../docs/AUN文档/AID空闲UDP待机详细设计.md)。
136
+
137
+ ## 6. 原生 MailClient 的三端移植
138
+
139
+ ### 6.1 认证、凭据和依赖
140
+
141
+ 原生客户端直连独立 SMTP STARTTLS/IMAPS,默认 `mail.{issuer}:587`/`mail.{issuer}:993`,使用 AID 证书、TLS 和 SASL EXTERNAL。连接准备 SMTP 与 IMAP,默认连接超时 10 秒、命令超时 30 秒;不能复用 Gateway JWT 替代证书认证。
142
+
143
+ | SDK | 凭据与信任根 | 实现/依赖 |
144
+ | --- | --- | --- |
145
+ | Python | provider 提供 PEM 或证书/私钥文件;`server_trust_bundle` 为 CA 文件路径 | [mail_client.py](../../python/src/aun_core/mail_client.py) |
146
+ | Node TS | provider 返回 `{cert, key}` string/Buffer;信任根是 CA 内容 | [mail-client.ts](../../ts/src/mail-client.ts);Nodemailer/ImapFlow |
147
+ | Go | provider 返回 `tls.Certificate`;信任根为 `[]byte` | [mail_client.go](../../go/mail_client.go);emersion SMTP/IMAP/SASL |
148
+
149
+ 每次使用当前 provider 快照,凭据变化后重建连接。Python 的 provider/文件读取失败归为 `identity_unavailable` 并断开旧连接;TLS、认证、协议错误保留原分层。Browser 没有原生 MailClient,旧 RPC 门面继续兼容。
150
+
151
+ ### 6.2 MIME、信封和发送结果
152
+
153
+ 结构化 MIME/附件与 raw MIME 都要保留独立信封、逐收件人结果和可选 Sent 副本。发送结果为 `accepted`/`partial`/`rejected`/`accepted_unknown`,Sent 状态独立为 `not_requested`/`saved`/`failed`/`unknown`;SMTP 接受不等于最终送达,Sent 失败不能回写成全部收件人拒绝。
154
+
155
+ Python raw MIME 保留原始头和正文字节,仅补缺失 Date/Message-ID;实际投递剥离 Bcc 及折行,Sent 保留完整副本。邮箱名使用 modified UTF-7,LIST 仅去一对协议引号。
156
+
157
+ Node 复制并规范化信封、去重收件人,不修改调用者对象。[ImapFlow 适配脚本](../../ts/scripts/patch-imapflow-external.mjs) 同时覆盖 ESM/CJS 的 SEARCH、COPY、MOVE、EXPUNGE、STORE;协议错误向上传播,合法空查询仍可成功,不能把查询失败吞成空结果。
158
+
159
+ ### 6.3 IMAP UID 与 watch 生命周期
160
+
161
+ UID 操作与流式读取应保持邮箱选择、UIDVALIDITY 和 UID 的关联。检查点字段、事件名和终止方式按各语言真实接口适配,不能只做大小写替换:
162
+
163
+ | SDK | watch 接口 | 变化事件/UIDVALIDITY 变化 |
164
+ | --- | --- | --- |
165
+ | Python | `watch(mailbox, uidvalidity, uid=0)` → AsyncIterator | `change`;`resync_required` 后结束迭代 |
166
+ | Node TS | `watch(mailbox, {uidValidity: bigint, uid: number}, signal?)` → AsyncGenerator | `changes`;`resync_required` 后重置 UID 并继续 |
167
+ | Go | `Watch(ctx, mailbox, MailWatchCheckpoint, consume)` | 初始 `sync`,后续 `changed`;`resync_required` 后内部结束 session,外层 Watch 返回 nil |
168
+
169
+ 收到 `resync_required` 应让应用重新建立该邮箱索引;不得跨 UIDVALIDITY 复用旧 UID。Python `fetch_stream`、Node `fetchStream`、Go `FetchStream` 的返回类型及关闭方式按源码接口实现。Go 回调错误向调用者返回,应用取消与内部重建信号不能误写为所有错误都无限重连。
170
+
171
+ 本版 Mail 整体验收尚未完成。默认 Go 运行镜像 `AUN_INCLUDE_MAIL=0` 未启用 Mail,但 build 阶段仍编译 Mail 代码,依赖裁剪不能只看运行镜像开关。
172
+
173
+ ## 7. 语言专属实现落点
174
+
175
+ | SDK | 本版内容 | 参考源码 |
176
+ | --- | --- | --- |
177
+ | Python | Windows extended path、pending 身份、名片缓存、group index 原子写入 | [keystore/_utils.py](../../python/src/aun_core/keystore/_utils.py)、[local_identity_store.py](../../python/src/aun_core/keystore/local_identity_store.py)、[agent_md.py](../../python/src/aun_core/agent_md.py)、[group_index.py](../../python/src/aun_core/group_index.py) |
178
+ | Python | HTTP 上传在 finally 关闭会话;闭环容量测试分离接受/投递指标并支持恢复 | [aid_store.py](../../python/src/aun_core/aid_store.py)、[bench_capacity.py](../../python/src/aun_cli/commands/bench_capacity.py)、[benchmark/runner.py](../../python/src/aun_cli/benchmark/runner.py) |
179
+ | Go | 已有 P-256 凭据只读接入、实例状态内存隔离;相同 PEM 空白变化可接受,实际换证书拒绝 | [client_readonly.go](../../go/client_readonly.go) |
180
+ | Go | DNS IP 回退保留原域名及显式端口 Host,HTTP/WS 自定义 CA | [transport.go](../../go/transport.go) |
181
+ | Go | busy timeout 先于 WAL 初始化;Ownership 归属恢复冲突详情 | [aid_db.go](../../go/keystore/aid_db.go)、[ownership_v21.go](../../go/ownership_v21.go) |
182
+
183
+ 只读身份的“只读”约束凭据存储,不限制网络 RPC 为只读。Python 闭环工具的阶梯上限、每路 pending、完整投递吞吐/P99、持续复验及 `--resume` 属于工具契约,不是 SDK 已证明的服务端容量。
184
+
185
+ ## 8. 定向回归与证据边界
186
+
187
+ | 范围 | 已有测试入口 | 核对重点 |
188
+ | --- | --- | --- |
189
+ | EventService | Python `tests/unit/test_pubsub_*.py`;TS/JS `tests/unit/pubsub-*.test.ts`;Go `pubsub_*_test.go` | 模式/授权求交、过滤替换与持久化、可信名片、本地容量/TTL、订阅代次 |
190
+ | ACK/同步 | Python `test_message_windows.py`/`test_client.py`;TS/JS client/delivery;Go `forward_commit_test.go` | 提交后 ACK、合并及失败重试、任务收尾、身份/连接隔离、背压和延迟恢复 |
191
+ | Echo | [规范](../protocol/echo-probe-sdk.md);TS/JS `tests/integration/echo.test.ts`;Go `integration_echo_test.go` | hop/trace、提前回送、未知投递、回调失败不重复诊断 |
192
+ | UDP | Python [test_udp_standby.py](../../python/tests/unit/test_udp_standby.py)/[codec 测试](../../python/tests/unit/test_udp_standby_codec.py);TS [udp-standby.test.ts](../../ts/tests/unit/udp-standby.test.ts);Go [udp_standby_test.go](../../go/udp_standby_test.go) | 严格协商、忙碌准入、订阅恢复、当前 ACK 新周期与抖动、超时和关闭 |
193
+ | Mail | Python [test_mail_client.py](../../python/tests/unit/test_mail_client.py);TS [mail-client.test.ts](../../ts/tests/unit/mail-client.test.ts);Go [mail_client_test.go](../../go/mail_client_test.go) | MIME/信封、逐收件人、Sent、错误分层、凭据轮换、UIDVALIDITY/watch |
194
+ | 语言专属 | Python `test_bench_capacity*.py` 及存储测试;Go [client_readonly_test.go](../../go/client_readonly_test.go) 与 transport 测试 | 工具指标/断点、Windows 路径、凭据只读、Host/CA、SQLite 初始化 |
195
+
196
+ 当前 Python 心跳行为可在 `aun-sdk-core/python/` 定向验证,临时输出应放在当前会话的临时目录:
197
+
198
+ ```powershell
199
+ python -X utf8 -m pytest tests/unit/test_udp_standby.py -k heartbeat -q -x -p no:cacheprovider --basetemp "$env:TMPDIR\pytest-udp-heartbeat"
200
+ ```
201
+
202
+ 本次上述命令 **11 项通过**,覆盖真实编解码收包路径下的周期更新。其余条目是现有测试入口,不表示本轮全部执行。此前版本一致性、JS conformance、Go E2EE 定向测试和 TS/JS 类型检查的记录见 [parity](../../python/CHANGES_FOR_PARITY.md#v0535),不能替代新功能全量验证。
203
+
204
+ 本次未启动 Kite/Docker,未运行公网、浏览器 live、跨域 E2E 或独立 Mail 整体验收;按单实例发布范围交付文档,不补做多实例实现或 Mail 服务功能。
@@ -1,6 +1,6 @@
1
1
  # AUN SDK - 快速开始
2
2
 
3
- **版本**: 0.4.5+ | **Python**: >= 3.11
3
+ **版本**: 0.5.34 | **Python**: >= 3.11
4
4
 
5
5
  ---
6
6
 
@@ -54,7 +54,7 @@ async def load_or_register(store: AIDStore, aid: str):
54
54
  if loaded["ok"]:
55
55
  return loaded["data"]["aid"]
56
56
 
57
- registered = await store.register(aid)
57
+ registered = await store.register(aid, type="human")
58
58
  if not registered["ok"]:
59
59
  raise RuntimeError(registered["error"]["message"])
60
60
 
@@ -65,10 +65,10 @@ async def load_or_register(store: AIDStore, aid: str):
65
65
 
66
66
 
67
67
  async def create_client(aid: str) -> AUNClient:
68
- store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
68
+ store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="", slot_id="main")
69
69
  identity = await load_or_register(store, aid)
70
70
  client = AUNClient(identity)
71
- await client.connect({"slot_id": "main", "auto_reconnect": True})
71
+ await client.connect({"auto_reconnect": True})
72
72
  return client
73
73
 
74
74
 
@@ -122,7 +122,7 @@ store = AIDStore(
122
122
  identity = store.load("alice.agentid.pub")["data"]["aid"]
123
123
  client = AUNClient(identity)
124
124
  client.set_protected_headers({"sdk": "python"})
125
- await client.connect({"slot_id": "main", "connection_kind": "long"})
125
+ await client.connect({"connection_kind": "long"})
126
126
  ```
127
127
 
128
128
  `verify_ssl` 在 `AIDStore` 构造时配置,不在 `AUNClient` 中配置。自动模式下 SDK 根据环境变量决定:
@@ -137,7 +137,7 @@ await client.connect({"slot_id": "main", "connection_kind": "long"})
137
137
 
138
138
  ## 数据目录布局
139
139
 
140
- SDK 使用 `{aun_path}/AIDs/{aid}/` 存储每个 AID 的专属数据:
140
+ Python / TypeScript(Node.js)/ Go 使用 `{aun_path}/AIDs/{aid}/` 存储每个 AID 的专属数据:
141
141
 
142
142
  ```text
143
143
  {aun_path}/
@@ -146,16 +146,17 @@ SDK 使用 `{aun_path}/AIDs/{aid}/` 存储每个 AID 的专属数据:
146
146
  ├── alice.agentid.pub/
147
147
  │ ├── private/key.json
148
148
  │ ├── public/cert.pem
149
- │ └── tokens/meta.json
149
+ │ └── aun.db
150
150
  └── bob.agentid.pub/
151
151
  ├── private/key.json
152
152
  ├── public/cert.pem
153
- └── tokens/meta.json
153
+ └── aun.db
154
154
  ```
155
155
 
156
156
  要点:
157
157
 
158
158
  - `aun_path` 是应用级目录,一个目录可管理多个 AID。
159
+ - token、消息游标、实例状态及 EventService 状态保存在身份目录的 SQLite `aun.db`;浏览器 JavaScript 使用 IndexedDB,不使用上述文件布局。
159
160
  - 不要用 AID 名称作为 `aun_path`,避免出现 `~/.aun/{aid}/AIDs/{aid}/` 冗余嵌套。
160
161
  - 私钥、令牌、群密钥等敏感数据由 SDK 的本地保护机制保存,不应手工删除或迁移单个文件。
161
162
 
@@ -183,11 +184,11 @@ Go:
183
184
 
184
185
  ```go
185
186
  store := aun.NewAIDStore("~/.aun/myapp", "")
186
- aid, err := store.Load("alice.agentid.pub")
187
- if err != nil {
188
- return err
187
+ loaded := store.Load("alice.agentid.pub")
188
+ if !loaded.Ok {
189
+ panic(loaded.Error)
189
190
  }
190
- client := aun.NewAUNClient(aid.Data.AID)
191
+ client := aun.NewAUNClient(loaded.Data.AID)
191
192
  ```
192
193
 
193
194
  ---
@@ -195,12 +196,14 @@ client := aun.NewAUNClient(aid.Data.AID)
195
196
  ## 核心流程
196
197
 
197
198
  1. 创建 `AIDStore`。
198
- 2. `store.load(aid)` 加载本地 AID;本地不存在时调用 `store.register(aid)` 后再次加载。
199
+ 2. `store.load(aid)` 加载本地 AID;本地不存在时调用 `store.register(aid, type="human")`(非 human 类型还需提供 `owner`)后再次加载。
199
200
  3. 用 AID 对象构造 `AUNClient(aid)`,或先 `AUNClient()` 再 `load_identity(aid)`。
200
201
  4. 先注册事件处理器,再调用 `connect(options)`。
201
202
  5. 通过 `call(method, params)` 执行业务 RPC。
202
203
  6. 通过 `close()` 释放连接和后台任务。
203
204
 
205
+ 事件发布订阅使用 `client.EventService`(Go 为 `client.EventService()`):Bus 宿主先 `start`,Pub/Sub 分别 `authorize`,然后发布或订阅;同一 client 可在同一 Bus 上绑定多个角色。完整流程及 SQLite/IndexedDB 恢复规则见 [AUN事件发布订阅应用集成指南](AUN事件发布订阅应用集成指南.md)。
206
+
204
207
  详细 API 见 [06-API手册.md](06-API手册.md),RPC 参数见各领域的 `09-*-rpc-manual.md`。
205
208
 
206
209
 
@@ -18,7 +18,7 @@ AID 是 Agent 的全局唯一身份,格式为域名形式,例如 `alice.agen
18
18
  ```python
19
19
  store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
20
20
 
21
- registered = await store.register("alice.agentid.pub")
21
+ registered = await store.register("alice.agentid.pub", type="human")
22
22
  loaded = store.load("alice.agentid.pub")
23
23
  me = loaded["data"]["aid"]
24
24
 
@@ -191,6 +191,18 @@ RPC 方法参数见 `09-message-rpc-manual.md`、`09-group-rpc-manual.md`、`09-
191
191
 
192
192
  ---
193
193
 
194
+ ## EventService 发布订阅
195
+
196
+ EventService 运行在 Bus AID 的 SDK 内,以 `(bus_aid, event_name)` 标识事件;Pub 向 Bus 发布 JSON 对象,Bus 按有效订阅向设备实例定向分发。同一 client 在同一 Bus 上可以同时承担 `bus`、`pub`、`sub`,发布与订阅分别授权;Bus 身份也须取得相应发布或订阅权限。
197
+
198
+ 四端默认持久保存 Bus 目录、白名单、可复核的授权与订阅,以及客户端授权材料、目录、订阅意图和待发布记录。Python / TypeScript(Node.js)/ Go 使用 SQLite,浏览器 JavaScript 使用 IndexedDB。启动先加载已有状态,再合并本次配置;恢复待发布记录沿用原 `event_id` 与 TTL,过期后记录失败,不重新发送。应用仍须重新启动 Bus 或按角色接入目标 Bus,SDK 不自动枚举历史 Bus。
199
+
200
+ 发布遵循“本地持久化成功 → 入队 → 后台发送 → 按所选回复模式确认成功 → 删除本地正文”。默认 `none` 表示 AUN 已接受发送,`accepted` 表示 Bus 已受理;两者均不表示订阅方已完成业务处理。Bus fanout、服务端 volatile 收件箱和事件历史不在本地待发布队列的恢复范围内。
201
+
202
+ `catalog` 查询事件定义;`publications` 查询本次 Bus 运行的首次受理汇总,`subscriptions` 查询当前有效订阅,授权目录不等于实际订阅。完整 API、可见范围及分页规则见 [API 手册](06-API手册.md#eventservice-事件发布订阅)与[应用集成指南](AUN事件发布订阅应用集成指南.md)。
203
+
204
+ ---
205
+
194
206
  ## Group Index 观察模型
195
207
 
196
208
  `group.index` 是群公告、群规则、入群要求和附件稳定引用的签名索引。它由 owner/admin 侧 SDK 生成并签名,Group 服务只校验、CAS 保存和在响应 `_meta.group_indexes` 中注入版本提示。
@@ -7,23 +7,23 @@
7
7
  重构后,注册、身份加载、会话连接分离:
8
8
 
9
9
  ```python
10
- store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="")
10
+ store = AIDStore(aun_path="~/.aun/myapp", encryption_seed="", slot_id="main")
11
11
 
12
12
  loaded = store.load(aid)
13
13
  if not loaded["ok"]:
14
- registered = await store.register(aid)
14
+ registered = await store.register(aid, type="human")
15
15
  if not registered["ok"]:
16
16
  raise RuntimeError(registered["error"]["message"])
17
17
  loaded = store.load(aid)
18
18
 
19
19
  me = loaded["data"]["aid"]
20
20
  client = AUNClient(me)
21
- await client.connect({"slot_id": "main", "auto_reconnect": True})
21
+ await client.connect({"auto_reconnect": True})
22
22
  ```
23
23
 
24
24
  关键约束:
25
25
 
26
- - `AIDStore.register(aid)` 只负责生成本地密钥、申请证书并落盘。
26
+ - `AIDStore.register(aid, *, type, owner=None, exttype=None)` 只负责生成本地密钥、申请证书并落盘;`type` 必填,非 `human` 类型还需按归属流程提供 `owner`。
27
27
  - `AIDStore.load(aid)` 返回 AID 值对象;AID 对象加载后不可变。
28
28
  - `AUNClient` 只接收 AID 对象,不接收字符串 AID 或配置字典里的 `aid` 字段。
29
29
  - `connect(options)` 内部会按需认证、建立 WebSocket、初始化 E2EE 和后台任务。
@@ -59,7 +59,7 @@ store = AIDStore(
59
59
  | 方法 | 说明 |
60
60
  |------|------|
61
61
  | `load(aid)` | 从本地加载 AID,返回 Result |
62
- | `register(aid)` | 注册新 AID,返回 Result |
62
+ | `register(aid, *, type, owner=None, exttype=None)` | 注册新 AID,返回 Result |
63
63
  | `list()` | 列出本地身份 |
64
64
  | `exists(aid)` | HEAD PKI 端点,判断 AID 是否已注册 |
65
65
  | `resolve(aid, opts=None)` | 解析身份与 agent.md,返回结构化 frontmatter;自有私钥身份优先本地草稿/缓存,可传 `{"skip_agent_md": True}` 跳过名片,或 `{"ownership": client}` 按需查询并缓存共识和 owner.md |
@@ -75,7 +75,7 @@ Result 使用方式:
75
75
  ```python
76
76
  result = await store.exists("alice.agentid.pub")
77
77
  if result["ok"] and not result["data"]["exists"]:
78
- await store.register("alice.agentid.pub")
78
+ await store.register("alice.agentid.pub", type="human")
79
79
  ```
80
80
 
81
81
  ---
@@ -143,7 +143,7 @@ await client.connect({
143
143
  | `extra_info` | 应用层自定义连接信息;下划线开头的键不会透传给 Gateway |
144
144
  | `background_sync` | 连接成功后是否执行消息后台补洞 / 未读同步,默认开启;不关闭已读状态查询补偿 |
145
145
  | `auto_reconnect` | 断线后是否自动重连 |
146
- | `heartbeat_interval` | 心跳间隔,秒 |
146
+ | `heartbeat_interval` | 保留的兼容选项;当前不启用 RPC 心跳,连接保活使用 WebSocket 控制帧 |
147
147
  | `retry.initial_delay` / `retry.max_delay` | 退避重连参数 |
148
148
  | `connect_timeout` / `call_timeout` | 连接和 RPC 超时,秒 |
149
149
  | `push_notify_aid` / `push_token` | Python SDK 推荐的离线推送登记入口;必须同时提供 |
@@ -151,6 +151,8 @@ await client.connect({
151
151
 
152
152
  `slot_id` 来自已加载的 AID,不是 `connect()` 选项。Python SDK 在 AUN 会话建立后把 `push_notify_aid` 映射为冻结 RPC 字段 `push_server_aid`,调用 `push.register` 登记当前 `(aid, device_id, slot_id)`;这些字段不会进入 `auth.connect`。登记失败时本次连接回滚并向调用方抛错。Go、TypeScript、JavaScript SDK 本轮未增加该便利入口。
153
153
 
154
+ 本表使用 Python 选项名;TS/JS 使用 `connectionKind`、`shortTtlMs`、`autoReconnect`、`backgroundSync` 等 camelCase 名称,Go 使用 `ConnectionOptions` 的 `ConnectionKind`、`ShortTTLMS`、`AutoReconnect`、`BackgroundSync` 等字段。
155
+
154
156
  当前稳定实现为 Gateway 模式;Peer / Relay 仍是协议能力定义,SDK 连接层会明确返回未实现。
155
157
 
156
158
  ---
@@ -180,6 +182,14 @@ await cli.close()
180
182
 
181
183
  ---
182
184
 
185
+ ## EventService 接入与恢复
186
+
187
+ EventService 使用已就绪的 AUNClient:Python / TS / JS 为 `client.EventService`,Go 为 `client.EventService()`。Bus 宿主调用 `start`,要求 Bus AID 等于当前身份;远端 Pub/Sub 直接 `authorize(bus_aid, role, ...)`,内部自动建立该角色客户端。多角色分别授权,使用独立的授权材料与租约。
188
+
189
+ 连接恢复时 SDK 会重新核验授权并恢复订阅和待发布队列;新进程仍需重新 `start` 本地 Bus,或对目标 Bus 的 Pub/Sub 角色调用 `authorize`。默认 SQLite/IndexedDB 保存待发布记录,恢复不延长 TTL,已过期记录转为可查询的失败结果。`close` 保留这些持久状态;停止接收新工作后可先 `drain` 再关闭。方法签名与目录查询见 [API 手册](06-API手册.md#eventservice-事件发布订阅),完整流程见 [应用集成指南](AUN事件发布订阅应用集成指南.md)。
190
+
191
+ ---
192
+
183
193
  ## 网关发现
184
194
 
185
195
  注册、解析和认证会根据 AID 的 issuer 自动发现 Gateway:
@@ -220,7 +230,7 @@ print(client.can_connect, client.can_send, client.is_online)
220
230
 
221
231
  ## Agent Web / agent.md
222
232
 
223
- 以下普通主体示例以本 AID 主签和 token 上传。Group/Org 名片由实体私钥生成主签,当前 owner 以本人 token 上传,无需实体登录;可选 owner 附签,存在就必须验全部块。Group 旧实体单签及实体身份上传始终兼容,Org 不开放该旧入口。取消实体额外 V2 上传授权,保留当前 owner、生命周期、实体证书代际与 CAS 检查,见 [协议 §2.5](../protocol/Ownership协议定义2.1.md#25-grouporg-名片的实体主签与-owner-上传)。
233
+ 以下普通主体示例以本 AID 主签和 token 上传。现代 Group/Org 名片由实体私钥生成主签,当前 owner 以本人 token 上传,无需实体登录;使用与 owner.md 配对的 ownership.statement,主签不含 signer_aid,也不要求旧 entity_cert_fingerprint,可选 owner 附签,存在就必须验全部块。Group 旧实体单签及实体身份上传持续兼容,Org 不开放该旧入口;仍保留当前 owner、生命周期、实体证书代际与 CAS 检查,见 [协议 §2.5](../protocol/Ownership协议定义2.1.md#25-grouporg-名片的实体主签与-owner-上传)。
224
234
 
225
235
  发布自己的 agent.md:
226
236
 
@@ -253,7 +263,7 @@ downloaded = await store.download_agent_md("bob.agentid.pub")
253
263
  state = await store.check_agent_md("bob.agentid.pub", ttl_days=1)
254
264
  ```
255
265
 
256
- 新 SDK 全部 NS GET/HEAD/PUT(含 fresh)携带 `X-AUN-Signature-Format: multi-v1` 获取完整多签;实体 fresh GET 必须同时携带 `X-AUN-Ownership-Check: 1`、`Cache-Control: no-cache`、`X-AUN-Signature-Format: multi-v1`;NS 仅凭 Check 头绕过 LRU 并新鲜验证全部签块,仍返回 not_applicable,不进入通用 Ownership 账本。无头客户端读取首签投影,表示 ETag 与完整存储 CAS 的映射见 [协议 §3.3](../protocol/Ownership协议定义2.1.md#33-读取并发与接口)。
266
+ 新 SDK 全部 NS GET/HEAD/PUT(含 fresh)携带 `X-AUN-Signature-Format: multi-v1` 获取完整多签;实体 fresh GET 必须同时携带 `X-AUN-Ownership-Check: 1`、`Cache-Control: no-cache`、`X-AUN-Signature-Format: multi-v1`;NS 凭 Check 头绕过 LRU 并新鲜验证全部签块。现代 Group/Org 参与双文件共识,缺少 ownership 的历史实体仍返回 not_applicable;普通关系管理 Facade 仍走专属生命周期边界。无头客户端读取首签投影,表示 ETag 与完整存储 CAS 的映射见 [协议 §3.3](../protocol/Ownership协议定义2.1.md#33-读取并发与接口)。
257
267
 
258
268
  当前公开入口分工固定:
259
269