@agentunion/fastaun-browser 0.5.19 → 0.5.21

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 (154) hide show
  1. package/CHANGELOG.md +176 -78
  2. package/_packed_docs/CHANGELOG.md +176 -78
  3. package/_packed_docs/INDEX.md +288 -269
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +101 -95
  5. package/_packed_docs/agent.md/SCHEMA.md +7 -7
  6. package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/344/270/216/346/215/242owner/347/274/226/346/216/222/346/226/271/346/241/210.md +530 -0
  7. package/_packed_docs/agent.md/working/AID/347/261/273/345/236/213-owner/345/205/263/347/263/273/345/256/214/346/225/264/350/256/276/350/256/241/344/270/216/345/256/236/346/226/275/350/256/241/345/210/222.md +685 -0
  8. package/_packed_docs/agent.md/working/agent.md-schema/344/270/216/347/255/276/345/217/221/351/252/214/347/255/276/346/265/201/347/250/213/346/276/204/346/270/205.md +349 -0
  9. package/_packed_docs/agent.md/working//346/234/254/345/234/260Docker/346/265/213/350/257/225Bug/346/270/205/345/215/225.md +40 -0
  10. package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +11 -11
  11. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +372 -331
  12. package/_packed_docs/protocol/08-AUN-E2EE.md +17 -12
  13. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +676 -676
  14. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +8 -12
  15. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +445 -0
  16. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
  17. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +666 -0
  18. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
  19. package/_packed_docs/protocol/agent.md/SCHEMA.md +1 -1
  20. package/_packed_docs/sdk/0.5.21-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +368 -0
  21. package/_packed_docs/sdk/0.5.21-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +350 -0
  22. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +1 -1
  23. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +5 -1
  24. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +64 -64
  25. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +70 -63
  26. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +43 -40
  27. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +179 -19
  28. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +50 -49
  29. package/_packed_docs/sdk/09-group-rpc-manual.md +261 -254
  30. package/_packed_docs/sdk/09-message-rpc-manual.md +253 -160
  31. package/_packed_docs/sdk/09-storage-rpc-manual.md +18 -26
  32. package/_packed_docs/sdk/09-/345/207/255/350/257/201/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +71 -0
  33. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +88 -0
  34. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +105 -92
  35. package/_packed_docs/sdk/INDEX.md +197 -167
  36. package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
  37. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
  38. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +930 -0
  39. package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
  40. 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 +363 -0
  41. 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 +553 -0
  42. package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +708 -0
  43. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +480 -0
  44. package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
  45. package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
  46. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +173 -0
  47. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +211 -0
  48. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/345/256/236/347/216/260/347/247/273/346/244/215/346/214/207/345/215/227.md +331 -0
  49. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +207 -0
  50. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212.md +252 -0
  51. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/345/256/236/346/226/275/350/256/241/345/210/222.md +156 -0
  52. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/346/226/271/346/241/210.md +273 -0
  53. package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/350/257/246/347/273/206/350/256/276/350/256/241.md +211 -0
  54. package/dist/agent-md-schema.d.ts +16 -4
  55. package/dist/agent-md-schema.d.ts.map +1 -1
  56. package/dist/agent-md-schema.js +65 -30
  57. package/dist/agent-md-schema.js.map +1 -1
  58. package/dist/agent-md.d.ts +35 -3
  59. package/dist/agent-md.d.ts.map +1 -1
  60. package/dist/agent-md.js +384 -150
  61. package/dist/agent-md.js.map +1 -1
  62. package/dist/aid-store.d.ts +59 -0
  63. package/dist/aid-store.d.ts.map +1 -1
  64. package/dist/aid-store.js +202 -16
  65. package/dist/aid-store.js.map +1 -1
  66. package/dist/aid.d.ts +4 -1
  67. package/dist/aid.d.ts.map +1 -1
  68. package/dist/aid.js +24 -42
  69. package/dist/aid.js.map +1 -1
  70. package/dist/auth.d.ts +1 -1
  71. package/dist/auth.d.ts.map +1 -1
  72. package/dist/auth.js +89 -18
  73. package/dist/auth.js.map +1 -1
  74. package/dist/bundle.js +6410 -1848
  75. package/dist/cert-utils.d.ts +50 -1
  76. package/dist/cert-utils.d.ts.map +1 -1
  77. package/dist/cert-utils.js +123 -56
  78. package/dist/cert-utils.js.map +1 -1
  79. package/dist/client/delivery.d.ts +108 -16
  80. package/dist/client/delivery.d.ts.map +1 -1
  81. package/dist/client/delivery.js +1411 -184
  82. package/dist/client/delivery.js.map +1 -1
  83. package/dist/client/rpc-pipeline.d.ts +4 -1
  84. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  85. package/dist/client/rpc-pipeline.js +203 -117
  86. package/dist/client/rpc-pipeline.js.map +1 -1
  87. package/dist/client/v2-e2ee.d.ts +22 -3
  88. package/dist/client/v2-e2ee.d.ts.map +1 -1
  89. package/dist/client/v2-e2ee.js +1312 -684
  90. package/dist/client/v2-e2ee.js.map +1 -1
  91. package/dist/client.d.ts +23 -2
  92. package/dist/client.d.ts.map +1 -1
  93. package/dist/client.js +419 -101
  94. package/dist/client.js.map +1 -1
  95. package/dist/config.d.ts +4 -0
  96. package/dist/config.d.ts.map +1 -1
  97. package/dist/config.js +1 -0
  98. package/dist/config.js.map +1 -1
  99. package/dist/crypto.d.ts.map +1 -1
  100. package/dist/crypto.js +8 -6
  101. package/dist/crypto.js.map +1 -1
  102. package/dist/events.d.ts +24 -3
  103. package/dist/events.d.ts.map +1 -1
  104. package/dist/events.js +171 -29
  105. package/dist/events.js.map +1 -1
  106. package/dist/facades.d.ts +42 -1
  107. package/dist/facades.d.ts.map +1 -1
  108. package/dist/facades.js +368 -12
  109. package/dist/facades.js.map +1 -1
  110. package/dist/index.d.ts +6 -4
  111. package/dist/index.d.ts.map +1 -1
  112. package/dist/index.js +1 -1
  113. package/dist/index.js.map +1 -1
  114. package/dist/keystore/index.d.ts +14 -1
  115. package/dist/keystore/index.d.ts.map +1 -1
  116. package/dist/keystore/indexeddb-identity-store.d.ts +4 -0
  117. package/dist/keystore/indexeddb-identity-store.d.ts.map +1 -1
  118. package/dist/keystore/indexeddb-identity-store.js +30 -13
  119. package/dist/keystore/indexeddb-identity-store.js.map +1 -1
  120. package/dist/keystore/indexeddb-shared.d.ts +19 -2
  121. package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
  122. package/dist/keystore/indexeddb-shared.js +193 -6
  123. package/dist/keystore/indexeddb-shared.js.map +1 -1
  124. package/dist/keystore/indexeddb-token-store.d.ts +15 -2
  125. package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
  126. package/dist/keystore/indexeddb-token-store.js +308 -27
  127. package/dist/keystore/indexeddb-token-store.js.map +1 -1
  128. package/dist/org-protocol.d.ts +45 -0
  129. package/dist/org-protocol.d.ts.map +1 -1
  130. package/dist/org-protocol.js +827 -21
  131. package/dist/org-protocol.js.map +1 -1
  132. package/dist/ownership-v21.d.ts +43 -9
  133. package/dist/ownership-v21.d.ts.map +1 -1
  134. package/dist/ownership-v21.js +183 -81
  135. package/dist/ownership-v21.js.map +1 -1
  136. package/dist/ownership-workflow.d.ts +36 -1
  137. package/dist/ownership-workflow.d.ts.map +1 -1
  138. package/dist/ownership-workflow.js +610 -89
  139. package/dist/ownership-workflow.js.map +1 -1
  140. package/dist/seq-tracker.d.ts +2 -0
  141. package/dist/seq-tracker.d.ts.map +1 -1
  142. package/dist/seq-tracker.js +3 -2
  143. package/dist/seq-tracker.js.map +1 -1
  144. package/dist/tools/cross-sdk-agent.d.ts +61 -3
  145. package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
  146. package/dist/tools/cross-sdk-agent.js +524 -45
  147. package/dist/tools/cross-sdk-agent.js.map +1 -1
  148. package/dist/transport.d.ts +4 -0
  149. package/dist/transport.d.ts.map +1 -1
  150. package/dist/transport.js +64 -30
  151. package/dist/transport.js.map +1 -1
  152. package/dist/version.d.ts +1 -1
  153. package/dist/version.js +1 -1
  154. package/package.json +1 -1
@@ -23,7 +23,7 @@ await client.connect({"slot_id": "main", "auto_reconnect": True})
23
23
 
24
24
  关键约束:
25
25
 
26
- - `AIDStore.register(aid)` 只负责生成本地密钥、申请证书并落盘。
26
+ - `AIDStore.register(aid)` 只负责生成本地密钥、申请证书并落盘。
27
27
  - `AIDStore.load(aid)` 返回 AID 值对象;AID 对象加载后不可变。
28
28
  - `AUNClient` 只接收 AID 对象,不接收字符串 AID 或配置字典里的 `aid` 字段。
29
29
  - `connect(options)` 内部会按需认证、建立 WebSocket、初始化 E2EE 和后台任务。
@@ -62,12 +62,14 @@ store = AIDStore(
62
62
  | `register(aid)` | 注册新 AID,返回 Result |
63
63
  | `list()` | 列出本地身份 |
64
64
  | `exists(aid)` | HEAD PKI 端点,判断 AID 是否已注册 |
65
- | `resolve(aid, opts=None)` | 拉取并缓存对端证书;默认同时下载并验签 agent.md,可传 `skip_agent_md=True` 跳过 |
65
+ | `resolve(aid, opts=None)` | 解析身份与 agent.md,返回结构化 frontmatter;自有私钥身份优先本地草稿/缓存,可传 `{"skip_agent_md": True}` 跳过名片,或 `{"ownership": client}` 按需查询并缓存共识和 owner.md |
66
66
  | `download_agent_md(aid)` | 下载并验签对端 agent.md |
67
67
  | `check_agent_md(aid, ttl_days=1)` | 检查本地缓存与远端 agent.md 状态 |
68
- | `diagnose(aid)` | 本地和远端一致性诊断 |
69
- | `renew_cert(aid)` / `rekey(aid)` | 证书续签和换钥,成功后重新 `load()` |
70
-
68
+ | `diagnose(aid)` | 本地和远端一致性诊断 |
69
+ | `renew_cert(aid)` / `rekey(aid)` | 证书续签和换钥,成功后重新 `load()` |
70
+
71
+ 自有私钥身份的 `resolve` 默认优先返回本地草稿或缓存,标记 `verification.status=unverified`、`source.agent_md_fetched=false`;草稿的 `in_sync=false`。需要读取远端权威内容时,显式调用 `download_agent_md` 或 `resolve(..., {"force_refresh": True})`,本地草稿仍保留;失败稿由应用显式重试上传,重连不自动重传。
72
+
71
73
  Result 使用方式:
72
74
 
73
75
  ```python
@@ -89,65 +91,65 @@ client.load_identity(me) # standby
89
91
  client = AUNClient(me) # standby
90
92
  ```
91
93
 
92
- `load_identity()` 只允许在 `no_identity` 或 `closed` 状态调用;传入对象必须是私钥有效的 AID。
93
-
94
+ `load_identity()` 只允许在 `no_identity` 或 `closed` 状态调用;传入对象必须是私钥有效的 AID。
95
+
94
96
  ### 显式认证
95
97
 
96
- 通常不需要单独调用认证,`connect()` 会自动完成。需要提前完成认证或检查认证链路时可调用:
98
+ 通常不需要单独调用认证,`connect()` 会自动完成。需要提前完成认证或检查认证链路时可调用:
97
99
 
98
100
  ```python
99
101
  auth = await client.authenticate()
100
102
  print(auth["access_token"], auth["gateway"])
101
103
  ```
102
104
 
103
- 认证成功后状态进入 `authenticated`,随后调用 `connect()` 建立会话。
104
-
105
- `authenticate()` 返回的 `access_token` 只是认证完成时的快照。后台刷新会更新 SDK 内部身份状态,但无法更新应用已经保存的字符串,因此不得把首次返回值长期用于 HTTP 请求。
106
-
107
- ### 读取当前 access token
108
-
109
- 应用绕过 SDK 门面、自行访问要求 AID Bearer 的 HTTP 数据面时,应在每次请求前同步读取当前缓存:
110
-
111
- ```python
112
- token = client.get_access_token() # str | None
113
- ```
114
-
115
- ```typescript
116
- const token = client.getAccessToken(); // string | null
117
- ```
118
-
119
- ```go
120
- token := client.GetAccessToken() // 缺失时为空字符串
121
- ```
122
-
123
- 这些 getter 只读取后台刷新任务维护的最新缓存,不发起认证、刷新或网络请求,也不独立检查 token 是否临近过期;其有效性依赖客户端连接生命周期和后台刷新任务正常运行。返回空值时应先完成身份加载和认证/连接,不得发送空 Bearer。应用不得跨请求长期保存 getter 的返回值;具体的数据面票据、跨域凭据和重试规则见 [Storage RPC 手册:数据面 HTTP 下载流程](09-storage-rpc-manual.md#数据面-http-下载流程)。
105
+ 认证成功后状态进入 `authenticated`,随后调用 `connect()` 建立会话。
106
+
107
+ `authenticate()` 返回的 `access_token` 只是认证完成时的快照。后台刷新会更新 SDK 内部身份状态,但无法更新应用已经保存的字符串,因此不得把首次返回值长期用于 HTTP 请求。
108
+
109
+ ### 读取当前 access token
110
+
111
+ 应用绕过 SDK 门面、自行访问要求 AID Bearer 的 HTTP 数据面时,应在每次请求前同步读取当前缓存:
112
+
113
+ ```python
114
+ token = client.get_access_token() # str | None
115
+ ```
116
+
117
+ ```typescript
118
+ const token = client.getAccessToken(); // string | null
119
+ ```
120
+
121
+ ```go
122
+ token := client.GetAccessToken() // 缺失时为空字符串
123
+ ```
124
+
125
+ 这些 getter 只读取后台刷新任务维护的最新缓存,不发起认证、刷新或网络请求,也不独立检查 token 是否临近过期;其有效性依赖客户端连接生命周期和后台刷新任务正常运行。返回空值时应先完成身份加载和认证/连接,不得发送空 Bearer。应用不得跨请求长期保存 getter 的返回值;具体的数据面票据、跨域凭据和重试规则见 [Storage RPC 手册:数据面 HTTP 下载流程](09-storage-rpc-manual.md#数据面-http-下载流程)。
124
126
 
125
127
  ### 连接
126
128
 
127
129
  ```python
128
- await client.connect({
129
- "connection_kind": "long",
130
- "auto_reconnect": True,
131
- "push_notify_aid": "push.example.com",
132
- "push_token": "opaque-token",
133
- })
130
+ await client.connect({
131
+ "connection_kind": "long",
132
+ "auto_reconnect": True,
133
+ "push_notify_aid": "push.example.com",
134
+ "push_token": "opaque-token",
135
+ })
134
136
  ```
135
137
 
136
138
  | 选项 | 说明 |
137
139
  |------|------|
138
- | `connection_kind` | `"long"` 或 `"short"` |
139
- | `short_ttl_ms` | 短连接服务端兜底超时 |
140
- | `delivery_mode` | 连接级投递语义 |
141
- | `extra_info` | 应用层自定义连接信息;下划线开头的键不会透传给 Gateway |
142
- | `background_sync` | 连接成功后是否执行消息后台补洞 / 未读同步,默认开启;不关闭已读状态查询补偿 |
143
- | `auto_reconnect` | 断线后是否自动重连 |
144
- | `heartbeat_interval` | 心跳间隔,秒 |
145
- | `retry.initial_delay` / `retry.max_delay` | 退避重连参数 |
146
- | `connect_timeout` / `call_timeout` | 连接和 RPC 超时,秒 |
147
- | `push_notify_aid` / `push_token` | Python SDK 推荐的离线推送登记入口;必须同时提供 |
148
- | `push_provider` / `push_app_id` | Python SDK 可选诊断字段 |
149
-
150
- `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 本轮未增加该便利入口。
140
+ | `connection_kind` | `"long"` 或 `"short"` |
141
+ | `short_ttl_ms` | 短连接服务端兜底超时 |
142
+ | `delivery_mode` | 连接级投递语义 |
143
+ | `extra_info` | 应用层自定义连接信息;下划线开头的键不会透传给 Gateway |
144
+ | `background_sync` | 连接成功后是否执行消息后台补洞 / 未读同步,默认开启;不关闭已读状态查询补偿 |
145
+ | `auto_reconnect` | 断线后是否自动重连 |
146
+ | `heartbeat_interval` | 心跳间隔,秒 |
147
+ | `retry.initial_delay` / `retry.max_delay` | 退避重连参数 |
148
+ | `connect_timeout` / `call_timeout` | 连接和 RPC 超时,秒 |
149
+ | `push_notify_aid` / `push_token` | Python SDK 推荐的离线推送登记入口;必须同时提供 |
150
+ | `push_provider` / `push_app_id` | Python SDK 可选诊断字段 |
151
+
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 本轮未增加该便利入口。
151
153
 
152
154
  当前稳定实现为 Gateway 模式;Peer / Relay 仍是协议能力定义,SDK 连接层会明确返回未实现。
153
155
 
@@ -160,16 +162,16 @@ await client.connect({
160
162
  长连接:
161
163
 
162
164
  ```python
163
- daemon = AUNClient(me)
164
- await daemon.connect({"connection_kind": "long"})
165
+ daemon = AUNClient(me)
166
+ await daemon.connect({"connection_kind": "long"})
165
167
  daemon.on("message.received", lambda e: print(e["payload"]))
166
168
  ```
167
169
 
168
170
  短连接:
169
171
 
170
172
  ```python
171
- cli = AUNClient(me)
172
- await cli.connect({"connection_kind": "short", "short_ttl_ms": 30000})
173
+ cli = AUNClient(me)
174
+ await cli.connect({"connection_kind": "short", "short_ttl_ms": 30000})
173
175
  await cli.call("message.send", {"to": peer, "payload": {"type": "text", "text": "hello"}})
174
176
  await cli.close()
175
177
  ```
@@ -206,19 +208,19 @@ print(client.can_connect, client.can_send, client.is_online)
206
208
  | `connection.error` | 连接、认证、重连错误 |
207
209
  | `token.refreshed` | token 自动刷新完成 |
208
210
  | `token.refresh_exhausted` | refresh_token 缺失、过期或刷新链耗尽,SDK 已清理本地 token,下一次重连会重新走完整登录 |
209
- | `message.received` | 收到消息 |
210
- | `group.changed` | 群组事件 |
211
- | `message.undecryptable` / `group.message_undecryptable` | E2EE 解密失败 |
212
- | `delivery.changed` | SDK 本地批量交付完成通知,用于合并 UI 刷新(完整契约见 [06-API手册](06-API手册.md#deliverychanged)) |
213
- | `read_state_sync` | SDK 本地已读状态补偿完成,含本轮 `owner_aid`、`states` 和逐项 `errors`;连接返回不代表补偿完成 |
214
-
215
- 建议在 `connect()` 前注册事件处理器。`read_state_sync` 只交付本轮成功查询涉及的去重状态及逐项错误,空查询不夹带旧缓存。AID/device 切换按身份代际隔离缓存、登记及补偿完成事件,A→B→A 也不能接受旧代际结果;原在途 RPC 仍可返回。
211
+ | `message.received` | 收到消息 |
212
+ | `group.changed` | 群组事件 |
213
+ | `message.undecryptable` / `group.message_undecryptable` | E2EE 解密失败 |
214
+ | `delivery.changed` | SDK 本地批量交付完成通知,用于合并 UI 刷新(完整契约见 [06-API手册](06-API手册.md#deliverychanged)) |
215
+ | `read_state_sync` | SDK 本地已读状态补偿完成,含本轮 `owner_aid`、`states` 和逐项 `errors`;连接返回不代表补偿完成 |
216
+
217
+ 建议在 `connect()` 前注册事件处理器。`read_state_sync` 只交付本轮成功查询涉及的去重状态及逐项错误,空查询不夹带旧缓存。AID/device 切换按身份代际隔离缓存、登记及补偿完成事件,A→B→A 也不能接受旧代际结果;原在途 RPC 仍可返回。
216
218
 
217
219
  ---
218
220
 
219
221
  ## Agent Web / agent.md
220
222
 
221
- 以下普通主体示例以本 AID 签名和 token 上传。Group/Org 使用专属 owner 生命周期:owner 与 entity_cert_fingerprint 必填、可无 ownership;仅当前 owner 用本人证书和私钥尾签(signer_aid=owner)并携带 V2 owner 授权,实体自身 token 不授予名片上传权。上传与恢复新鲜核对 owner/状态及实体证书代际,格式见 [Ownership 协议 §2.5](../protocol/Ownership协议定义2.1.md#25-grouporg-名片的-owner-代签与上传)。
223
+ 以下普通主体示例以本 AID 主签和 token 上传。Group/Org 名片由实体私钥生成主签,当前 owner 以本人 token 上传,无需实体登录;可选 owner 附签,存在就必须验全部块。Group 旧实体单签及实体身份上传始终兼容,Org 不开放该旧入口。取消实体额外 V2 上传授权,保留当前 owner、生命周期、实体证书代际与 CAS 检查,见 [协议 §2.5](../protocol/Ownership协议定义2.1.md#25-grouporg-名片的实体主签与-owner-上传)。
222
224
 
223
225
  发布自己的 agent.md:
224
226
 
@@ -226,16 +228,19 @@ print(client.can_connect, client.can_send, client.is_online)
226
228
  uploaded = await store.upload_agent_md("alice.agentid.pub", content)
227
229
  ```
228
230
 
229
- `aid` 必须是本地 AID。上传由 `AIDStore` 读取本地私钥签名,并通过 `AuthFlow` 获取或复用该 AID 的 access_token。
230
-
231
+ `aid` 必须是本地 AID。上传由 `AIDStore` 读取本地私钥签名,并通过 `AuthFlow` 获取或复用该 AID 的 access_token。
232
+
231
233
  解析对端并验签 agent.md:
232
234
 
233
235
  ```python
234
236
  resolved = await store.resolve("bob.agentid.pub")
235
237
  if resolved["ok"]:
238
+ print(resolved["data"]["agent_md"]["frontmatter"].get("name"))
236
239
  print(resolved["data"]["agent_md"]["verification"]["status"])
237
240
  ```
238
241
 
242
+ frontmatter 保留原文的标准字段、扩展字段及其类型,历史名片缺字段不补默认值。需要 ownership 时传入已有 client:`await store.resolve("bob.agentid.pub", {"ownership": client})`,读取 `data.ownership.status`;复用既有双文件共识校验,默认缓存 60 秒,包含读取到的 owner.md 原文。`ownership_ttl_ms=0` 禁止复用,`force_refresh=True` 同时绕过共识缓存;缓存不用于授权。完整 opts、字段、状态及四语言差异见 [resolve 输入与输出](06-API手册.md#resolve-输入与输出)。
243
+
239
244
  只下载对端 agent.md:
240
245
 
241
246
  ```python
@@ -248,11 +253,13 @@ downloaded = await store.download_agent_md("bob.agentid.pub")
248
253
  state = await store.check_agent_md("bob.agentid.pub", ttl_days=1)
249
254
  ```
250
255
 
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-读取并发与接口)。
257
+
251
258
  当前公开入口分工固定:
252
259
 
253
260
  | 主体 | 公开能力 |
254
261
  |------|----------|
255
- | `AIDStore` | `upload_agent_md(aid, content=None)`、`download_agent_md(aid)`、`check_agent_md(aid, ttl_days=1)`、`resolve(aid, opts)` |
262
+ | `AIDStore` | `sign/verify` 通用 raw/document 签验、`upload_agent_md(aid, content=None)`、`download_agent_md(aid)`、`check_agent_md(aid, ttl_days=1)`、`resolve(aid, opts)` |
256
263
  | `AID` | `sign_agent_md(content)`、`verify_agent_md(content)` 低层签验能力 |
257
264
  | `AUNClient` | 连接、事件和 RPC 调用;不再暴露 agent.md 上传入口 |
258
265
 
@@ -41,20 +41,22 @@ await client.call("message.send", {
41
41
  })
42
42
  ```
43
43
 
44
- 当前 SDK 使用 E2EE V2 多设备 wrap 主路径:
45
-
46
- 1. 发送前通过 `message.v2.bootstrap` 或 `group.v2.bootstrap` 获取接收方当前活跃设备、设备 prekey、self-sync 设备和 audit recipients。
47
- 2. SDK 为每条消息生成独立 `master_key`、消息 nonce 和发送方临时 session key,只加密一次正文。
48
- 3. SDK 为每个接收设备生成一条 recipient wrap。设备有可用 SPK 时使用 `3DH` wrap;缺少 SPK 的兼容场景才使用 `1DH` wrap。
49
- 4. E2EE 信封包含 `sender_signature`、AAD、`recipients_digest` / Merkle proof,接收端必须验签、验 AAD、验 recipient proof 后再解密。
50
-
51
- 每条消息独立密钥;V2 当前主路径不再使用旧 `prekey_ecdh_v2` / `long_term_key` 信封作为默认发送格式。旧术语只用于历史兼容文档或迁移排查。
52
-
53
- 接收端校验签名需要发送方 IK。若本地 session 和 PKI 证书都没有目标 sender/device 的 IK,Python、TypeScript、Go、JavaScript SDK 会先给当前消息一次有界同步补救机会:同一发送端的并发请求通过 single-flight 合并,最多阻塞 3 秒调用 `message.v2.bootstrap`;群消息仍未命中时再调用 `group.v2.bootstrap`。获取成功后立即重试当前消息解密;获取失败或超时才进入原有 pending 后台重试,History 则返回结构化解密失败项而不进入实时 pending。该补救会增加少量首条消息延迟,但避免冷启动时“消息已 ACK、IK 稍后才到、当前消息无回调”。
54
-
55
- 同步获取失败意味着当前时点仍不具备验签和解密条件,SDK 不伪造明文,也不因永久坏密文阻塞 Forward/Tail 水位。实时消息通过 `message.undecryptable` / `group.message_undecryptable` 暴露诊断;应用仍需按 `message_id` 幂等处理后续 pending 重试可能产生的补交付。
56
-
57
- ## ProtectedHeaders 与可验证上下文
44
+ 当前 SDK 使用 E2EE V2 多设备 wrap 主路径:
45
+
46
+ 1. 发送前通过 `message.v2.bootstrap` 或 `group.v2.bootstrap` 获取接收方当前活跃设备、设备 prekey、self-sync 设备和 audit recipients。
47
+ 2. SDK 为每条消息生成独立 `master_key`、消息 nonce 和发送方临时 session key,只加密一次正文。
48
+ 3. SDK 为每个接收设备生成一条 recipient wrap。设备有可用 SPK 时使用 `3DH` wrap;缺少 SPK 的兼容场景才使用 `1DH` wrap。
49
+ 4. E2EE 信封包含 `sender_signature`、AAD、`recipients_digest` / Merkle proof,接收端必须验签、验 AAD、验 recipient proof 后再解密。
50
+
51
+ 每条消息独立密钥;V2 当前主路径不再使用旧 `prekey_ecdh_v2` / `long_term_key` 信封作为默认发送格式。旧术语只用于历史兼容文档或迁移排查。
52
+
53
+ 接收端校验签名需要发送方 IK。若本地 session 和 PKI 证书都没有目标 sender/device 的 IK,Python、TypeScript、Go、JavaScript SDK 会先给当前消息一次有界同步补救机会:同一发送端的并发请求通过 single-flight 合并,最多阻塞 3 秒调用 `message.v2.bootstrap`;群消息仍未命中时再调用 `group.v2.bootstrap`。获取成功后立即重试当前消息解密;获取失败或超时才进入原有 pending 后台重试,History 则返回结构化解密失败项而不进入实时 pending。该补救会增加少量首条消息延迟,但避免冷启动时“消息已 ACK、IK 稍后才到、当前消息无回调”。
54
+
55
+ 同步获取失败意味着当前时点仍不具备验签和解密条件,SDK 不伪造明文。P2P peer 路径不能仅凭扫描证明越过未成功解密或交付的消息,永久坏密文同样不推进该处 A/ACK;Group 保持原有终态规则。实时消息通过 `message.undecryptable` / `group.message_undecryptable` 暴露诊断;应用仍需按消息业务身份幂等处理后续 pending 重试可能产生的补交付。
56
+
57
+ ## ProtectedHeaders 与可验证上下文
58
+
59
+ `message.send` / `group.send` 的可选 `need_render` 默认 `true`,由 SDK 提取到外层信封;缺字段及历史 NULL 也按 `true`。它是展示/统计提示,不进入 AAD、`protected_headers`、消息保护签名或元数据 HMAC。RPC `client_signature` 仍按既有完整业务参数规则覆盖它,不能因为不进 AAD 就从 RPC canonical 中排除。
58
60
 
59
61
  `protected_headers` 是 E2EE 信封里的可选元数据字典,语义接近 HTTP headers:适合放 `device_id`、`slot_id`、`device_name`、`os`、`sdk_version`、`app_name` 等需要被接收端识别、且需要防篡改的非业务内容。`payload` 仍然类似 HTTP body,业务内容应放在 `payload` 内。
60
62
 
@@ -69,11 +71,11 @@ await client.call("message.send", {
69
71
 
70
72
  `payload_type` 不需要应用层传入。SDK 会读取加密前 `payload.type`,自动写入 `protected_headers.payload_type`,接收端解密后会校验它与明文 `payload.type` 一致。
71
73
 
72
- `protected_headers` / `headers` 是 send/thought 参数的顶层字段,不放入单独的 `envelope` 入参对象,也不属于业务 `payload`。裸 WebSocket 客户端若自行发送已加密信封,需要把 protected headers 放在自构造的 E2EE 信封内并自行完成 `_auth`,服务端不会替裸 RPC 调用生成或校验明文侧的 protected headers。
73
-
74
- `agent_md` 是独立于 E2EE 的版本提示元数据,不属于 `protected_headers`,也不参与 AAD 或业务鉴权。当前 Message Service V2 P2P 信封可携带 `agent_md.sender`;SDK 也识别 `agent_md.group`。Gateway 在 RPC response / event push 的 `_meta.agent_md_etags` 中注入 `requester`、`peer`、`group`,四端 SDK 会自动写入对应 AID 的 `remote_etag` / `last_modified`,后续仍以下载后的 agent.md 签名验证作为可信依据。
75
-
76
- 示例:
74
+ `protected_headers` / `headers` 是 send/thought 参数的顶层字段,不放入单独的 `envelope` 入参对象,也不属于业务 `payload`。裸 WebSocket 客户端若自行发送已加密信封,需要把 protected headers 放在自构造的 E2EE 信封内并自行完成 `_auth`,服务端不会替裸 RPC 调用生成或校验明文侧的 protected headers。
75
+
76
+ `agent_md` 是独立于 E2EE 的版本提示元数据,不属于 `protected_headers`,也不参与 AAD 或业务鉴权。当前 Message Service V2 P2P 信封可携带 `agent_md.sender`;SDK 也识别 `agent_md.group`。Gateway 在 RPC response / event push 的 `_meta.agent_md_etags` 中注入 `requester`、`peer`、`group`,四端 SDK 会自动写入对应 AID 的 `remote_etag` / `last_modified`,后续仍以下载后的 agent.md 签名验证作为可信依据。
77
+
78
+ 示例:
77
79
 
78
80
  ```python
79
81
  from aun_core import ProtectedHeaders
@@ -109,8 +111,8 @@ await client.call("group.send", {
109
111
 
110
112
  ```json
111
113
  {
112
- "type": "e2ee.p2p_encrypted",
113
- "version": "v2",
114
+ "type": "e2ee.p2p_encrypted",
115
+ "version": "v2",
114
116
  "ciphertext": "...",
115
117
  "protected_headers": {
116
118
  "device_id": "dev-123",
@@ -134,8 +136,8 @@ await client.call("group.send", {
134
136
 
135
137
  计算规则:
136
138
 
137
- 1. 解密流程会得到本条消息的 `master_key`。
138
- 2. `metadata_key = HMAC-SHA256(master_key, "aun-envelope-metadata-key-v1")`。
139
+ 1. 解密流程会得到本条消息的 `master_key`。
140
+ 2. `metadata_key = HMAC-SHA256(master_key, "aun-envelope-metadata-key-v1")`。
139
141
  3. 对字典去掉 `_auth` 后做 canonical JSON:UTF-8、key 排序、紧凑分隔符。
140
142
  4. `tag = HMAC-SHA256(metadata_key, domain + "\0" + canonical_json(body))`。
141
143
  5. `domain` 对 `protected_headers` 为 `aun-protected-headers-v1`,对 `context` 为 `aun-protected-context-v1`。
@@ -292,7 +294,7 @@ client.on("message.received", handler)
292
294
  `message.pull` 返回的消息已自动解密:
293
295
 
294
296
  ```python
295
- result = await client.call("message.pull", {"after_seq": 0, "limit": 50})
297
+ result = await client.call("message.pull", {"sender_aid": "alice.agentid.pub", "limit": 200})
296
298
  for msg in result["messages"]:
297
299
  if msg.get("encrypted"):
298
300
  print(f"加密消息: {msg['payload']}")
@@ -301,20 +303,21 @@ for msg in result["messages"]:
301
303
 
302
304
  ---
303
305
 
304
- ## V2 设备公钥与 SPK 管理
305
-
306
- 连接成功后,SDK 会初始化本设备 V2 session,生成或加载 IK / SPK,并通过 `message.v2.put_peer_pk` 幂等注册当前 P2P 设备 SPK。群组路径会按群生成独立 group SPK,并通过 `group.v2.put_group_pk` 注册。应用层一般无需手动管理这些密钥。
307
-
308
- 当前主路径的要点:
309
-
310
- - P2P 设备 SPK 的 `key_source` 为 `peer_device_prekey`,由 AID 私钥签名背书。
311
- - 群内独立 group SPK 的 `key_source` 为 `group_device_prekey`,按规范化后的 `group_aid` 隔离。
312
- - SDK 发送前通过 `message.v2.bootstrap` / `group.v2.bootstrap` 获取目标设备集合和当前 SPK。
313
- - 旧 SPK 会在本地保留一段安全窗口,用于解密引用旧 SPK 的历史消息;满足已消费和保留窗口条件后才销毁。
314
-
315
- 裸 WebSocket 客户端如果绕过 SDK,需要自行完成同等的 SPK 生成、AID 私钥签名、注册和 bootstrap 逻辑。旧 `message.e2ee.put_prekey/get_prekey` 只用于 legacy `prekey_ecdh_v2` 信封兼容,不是当前 SDK 的默认路径。
316
-
317
- SPK 签名里的 `spk_timestamp` 使用 Unix 秒;消息、群事件和服务端 `timestamp` / `created_at` 等主路径时间字段仍使用 Unix 毫秒。
306
+ ## V2 设备公钥与 SPK 管理
307
+
308
+ 连接成功后,SDK 会初始化本设备 V2 session,生成或加载 IK / SPK,并通过 `message.v2.put_peer_pk` 幂等注册当前 P2P 设备 SPK。群组路径会按群生成独立 group SPK,并通过 `group.v2.put_group_pk` 注册。应用层一般无需手动管理这些密钥。
309
+
310
+ 当前主路径的要点:
311
+
312
+ - P2P 设备 SPK 的 `key_source` 为 `peer_device_prekey`,由 AID 私钥签名背书。
313
+ - 群内独立 group SPK 的 `key_source` 为 `group_device_prekey`,按规范化后的 `group_aid` 隔离。
314
+ - SDK 发送前通过 `message.v2.bootstrap` / `group.v2.bootstrap` 获取目标设备集合和当前 SPK;P2P 定向设备未命中缓存时的单次新鲜重试与失败边界见 [message.send](09-message-rpc-manual.md#messagesend)。
315
+ - 旧 SPK 会在本地保留一段安全窗口,用于解密引用旧 SPK 的历史消息;满足已消费和保留窗口条件后才销毁。
316
+ - peer 拉取保留原 seq 与历史密文,不更改 AAD。peer ACK 和 slot 级 `legacy_safe_ack_seq` 不是设备全部消费 slot 的安全证明;当前实现可省略 `device_safe_ack_seq`,SDK 不据前两者销毁旧 SPK。
317
+
318
+ 裸 WebSocket 客户端如果绕过 SDK,需要自行完成同等的 SPK 生成、AID 私钥签名、注册和 bootstrap 逻辑。旧 `message.e2ee.put_prekey/get_prekey` 只用于 legacy `prekey_ecdh_v2` 信封兼容,不是当前 SDK 的默认路径。
319
+
320
+ SPK 签名里的 `spk_timestamp` 使用 Unix 秒;消息、群事件和服务端 `timestamp` / `created_at` 等主路径时间字段仍使用 Unix 毫秒。
318
321
 
319
322
  ---
320
323
 
@@ -364,7 +367,7 @@ client = AUNClient(aid)
364
367
  | P2P 消息默认要求发送方签名 | 无 `sender_signature` 的消息被拒绝 |
365
368
  | 群组消息默认要求发送方签名 | `require_signature=True`,无签名或无发送方证书的消息被拒绝 |
366
369
  | 群组 E2EE 为固定启用能力 | `group_e2ee=true`,不可关闭 |
367
- | 默认要求前向保密 | V2 优先使用设备 SPK 的 `3DH` wrap;缺少 SPK 的 `1DH` 路径仅作为兼容降级 |
368
- | 客户端操作签名 | SDK 会为关键操作附加 `client_signature`;Gateway 对 `send/pull/ack` 等常规 RPC 优先使用连接级身份认证,只有身份声明与连接不一致、敏感操作、能力身份或主动携签场景才执行 ECDSA 验签 |
370
+ | 默认要求前向保密 | V2 优先使用设备 SPK 的 `3DH` wrap;缺少 SPK 的 `1DH` 路径仅作为兼容降级 |
371
+ | 客户端操作签名 | SDK 会为关键操作附加 `client_signature`;Gateway 对 `send/pull/ack` 等常规 RPC 优先使用连接级身份认证,只有身份声明与连接不一致、敏感操作、能力身份或主动携签场景才执行 ECDSA 验签 |
369
372
 
370
373