@agentunion/fastaun-browser 0.5.19 → 0.5.20

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 (114) hide show
  1. package/CHANGELOG.md +129 -78
  2. package/_packed_docs/CHANGELOG.md +129 -78
  3. package/_packed_docs/INDEX.md +201 -195
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +93 -90
  5. package/_packed_docs/agent.md/SCHEMA.md +7 -7
  6. 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
  7. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1072 -1072
  8. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +676 -676
  9. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +8 -12
  10. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +443 -0
  11. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
  12. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +658 -0
  13. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
  14. package/_packed_docs/protocol/agent.md/SCHEMA.md +1 -1
  15. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +1 -1
  16. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +67 -63
  17. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +1 -1
  18. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +35 -8
  19. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
  20. package/_packed_docs/sdk/09-group-rpc-manual.md +258 -254
  21. package/_packed_docs/sdk/09-message-rpc-manual.md +7 -4
  22. package/_packed_docs/sdk/09-storage-rpc-manual.md +18 -26
  23. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +61 -52
  24. package/_packed_docs/sdk/INDEX.md +92 -80
  25. package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
  26. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
  27. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +922 -0
  28. package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
  29. 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 +300 -0
  30. 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 +382 -0
  31. 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
  32. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +476 -0
  33. package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
  34. package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. 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
  43. package/dist/agent-md-schema.d.ts +15 -4
  44. package/dist/agent-md-schema.d.ts.map +1 -1
  45. package/dist/agent-md-schema.js +64 -30
  46. package/dist/agent-md-schema.js.map +1 -1
  47. package/dist/agent-md.d.ts +10 -2
  48. package/dist/agent-md.d.ts.map +1 -1
  49. package/dist/agent-md.js +278 -121
  50. package/dist/agent-md.js.map +1 -1
  51. package/dist/aid-store.d.ts +46 -0
  52. package/dist/aid-store.d.ts.map +1 -1
  53. package/dist/aid-store.js +149 -10
  54. package/dist/aid-store.js.map +1 -1
  55. package/dist/aid.d.ts +4 -1
  56. package/dist/aid.d.ts.map +1 -1
  57. package/dist/aid.js +23 -42
  58. package/dist/aid.js.map +1 -1
  59. package/dist/auth.d.ts +1 -1
  60. package/dist/auth.d.ts.map +1 -1
  61. package/dist/auth.js +85 -18
  62. package/dist/auth.js.map +1 -1
  63. package/dist/bundle.js +1581 -781
  64. package/dist/cert-utils.d.ts +49 -1
  65. package/dist/cert-utils.d.ts.map +1 -1
  66. package/dist/cert-utils.js +102 -56
  67. package/dist/cert-utils.js.map +1 -1
  68. package/dist/client/delivery.d.ts +7 -0
  69. package/dist/client/delivery.d.ts.map +1 -1
  70. package/dist/client/delivery.js +243 -28
  71. package/dist/client/delivery.js.map +1 -1
  72. package/dist/client/rpc-pipeline.d.ts.map +1 -1
  73. package/dist/client/rpc-pipeline.js +89 -77
  74. package/dist/client/rpc-pipeline.js.map +1 -1
  75. package/dist/client/v2-e2ee.d.ts.map +1 -1
  76. package/dist/client/v2-e2ee.js +99 -80
  77. package/dist/client/v2-e2ee.js.map +1 -1
  78. package/dist/client.d.ts.map +1 -1
  79. package/dist/client.js +31 -17
  80. package/dist/client.js.map +1 -1
  81. package/dist/crypto.d.ts.map +1 -1
  82. package/dist/crypto.js +8 -6
  83. package/dist/crypto.js.map +1 -1
  84. package/dist/events.d.ts +5 -2
  85. package/dist/events.d.ts.map +1 -1
  86. package/dist/events.js +33 -14
  87. package/dist/events.js.map +1 -1
  88. package/dist/facades.js +5 -5
  89. package/dist/facades.js.map +1 -1
  90. package/dist/index.d.ts +1 -1
  91. package/dist/index.d.ts.map +1 -1
  92. package/dist/index.js.map +1 -1
  93. package/dist/org-protocol.d.ts.map +1 -1
  94. package/dist/org-protocol.js +72 -12
  95. package/dist/org-protocol.js.map +1 -1
  96. package/dist/ownership-v21.d.ts +25 -8
  97. package/dist/ownership-v21.d.ts.map +1 -1
  98. package/dist/ownership-v21.js +142 -73
  99. package/dist/ownership-v21.js.map +1 -1
  100. package/dist/ownership-workflow.d.ts +6 -1
  101. package/dist/ownership-workflow.d.ts.map +1 -1
  102. package/dist/ownership-workflow.js +221 -58
  103. package/dist/ownership-workflow.js.map +1 -1
  104. package/dist/tools/cross-sdk-agent.d.ts +2 -1
  105. package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
  106. package/dist/tools/cross-sdk-agent.js +91 -8
  107. package/dist/tools/cross-sdk-agent.js.map +1 -1
  108. package/dist/transport.d.ts +1 -0
  109. package/dist/transport.d.ts.map +1 -1
  110. package/dist/transport.js +2 -0
  111. package/dist/transport.js.map +1 -1
  112. package/dist/version.d.ts +1 -1
  113. package/dist/version.js +1 -1
  114. package/package.json +1 -1
@@ -0,0 +1,270 @@
1
+ # Ownership SDK集成指南
2
+
3
+ 本文是 legacy 集成记录,实现基准为 2026-10-09 工作区代码,不代表当前 Ownership 2.1。当前应用接入、审批及新鲜共识见 [Ownership 2.1 SDK 应用集成指南](Ownership2.1-SDK应用集成指南.md);下文旧 proof、自动 escrow 和代上传流程不能作为 2.1 接入方式。
4
+
5
+ ## 1. TypeScript快速集成
6
+
7
+ ### 1.1 加载双方身份
8
+
9
+ 示例使用Node.js SDK `@agentunion/fastaun`,当前源码要求Node.js >= 22.16.0。owner与subject已经注册,分别持有自己的证书和私钥;将示例AID、数据目录及密钥保护种子替换为应用已有配置。两端通常运行在不同进程,下面并列展示各自的接入代码。
10
+
11
+ ```bash
12
+ npm install @agentunion/fastaun
13
+ ```
14
+
15
+ ```ts
16
+ import { AIDStore, AUNClient } from '@agentunion/fastaun';
17
+
18
+ function loadClient(store: AIDStore, aid: string): AUNClient {
19
+ const loaded = store.load(aid);
20
+ if (!loaded.ok) throw new Error(loaded.error.message);
21
+ return new AUNClient(loaded.data.aid);
22
+ }
23
+ ```
24
+
25
+ ```ts
26
+ const ownerStore = new AIDStore({ aunPath: './.aun-owner', encryptionSeed: process.env.OWNER_KEY_SEED ?? '', verifySsl: true });
27
+ const subjectStore = new AIDStore({ aunPath: './.aun-subject', encryptionSeed: process.env.SUBJECT_KEY_SEED ?? '', verifySsl: true });
28
+ const owner = loadClient(ownerStore, 'owner.agentid.pub');
29
+ const subject = loadClient(subjectStore, 'subject.agentid.pub');
30
+ ```
31
+
32
+ `OWNER_KEY_SEED`、`SUBJECT_KEY_SEED`是本示例的应用环境变量,用于读取已有身份的保护种子。`AUNClient`接收`AID`对象;`store.load()`是同步方法,返回`Result`,联网的绑定方法则是异步方法。
33
+
34
+ ### 1.2 接入应用审批,再连接
35
+
36
+ 接收方订阅`ownership.request`。SDK已经验证申请声明,事件直接传入请求字段;应用将它接入确认界面或自己的审批逻辑。接受关系会继续自动托管subject的完整identity,其中包含私钥,审批界面应让使用者理解这项授权。
37
+
38
+ ```ts
39
+ function subscribeRequests(client: AUNClient): void {
40
+ client.on('ownership.request', (payload) => {
41
+ const request = payload as { request_id: string; requester_aid: string };
42
+ console.log('待审批的ownership申请', request);
43
+ });
44
+ }
45
+ subscribeRequests(owner);
46
+ subscribeRequests(subject);
47
+ ```
48
+
49
+ 以下函数供应用的接受/拒绝操作调用。`requestId`取自对应客户端收到的事件;`extensions`写入接受方自己的签名声明。
50
+
51
+ ```ts
52
+ async function decideOwnership(client: AUNClient, requestId: string, accepted: boolean) {
53
+ if (accepted) return client.acceptOwnershipRequest(requestId, {
54
+ extensions: { application: 'clinic-app' },
55
+ });
56
+ return client.rejectOwnershipRequest(requestId);
57
+ }
58
+ await Promise.all([owner.connect(), subject.connect()]);
59
+ ```
60
+
61
+ 监听器在`connect()`前注册,便于接收连接恢复时重新发布的待审批申请。应用回调收到的是请求对象,不需要再读取一层`payload`。
62
+
63
+ ### 1.3 owner发起绑定
64
+
65
+ owner应用执行:
66
+
67
+ ```ts
68
+ const sent = await owner.bindAid('subject.agentid.pub', {
69
+ subjectType: 'agent',
70
+ requestId: 'clinic-bind-001',
71
+ extensions: { department: 'clinic' },
72
+ });
73
+ console.log('绑定申请发送结果', sent);
74
+ ```
75
+
76
+ subject应用收到事件后,使用事件中的`request_id`调用`decideOwnership(subject, request_id, true)`或`decideOwnership(subject, request_id, false)`。接受后,SDK自动回复、发布关系名片、托管identity并推进owner代上传;应用只需完成一次审批。
77
+
78
+ `await bindAid()`表示申请的消息发送调用结束,双方关系的完成需要等待接受方确认。这个区别与IM系统的“消息发送成功”和“对方已处理”相同。
79
+
80
+ ### 1.4 subject发起绑定
81
+
82
+ 也可以由subject应用发起,作为上一节的另一种入口:
83
+
84
+ ```ts
85
+ await subject.bindOwner('owner.agentid.pub', {
86
+ subjectType: 'agent',
87
+ extensions: { application: 'clinic-app' },
88
+ });
89
+ ```
90
+
91
+ 这时由owner应用处理`ownership.request`,调用`decideOwnership(owner, request_id, accepted)`。subject SDK会先尝试上传只有subject签名的关系名片,然后等待owner确认。`subjectType`是本次关系记录的类型信息;SDK修改已有名片时保留原有`type`、其它frontmatter和正文,它不是通用的类型修改入口。
92
+
93
+ ### 1.5 查询本地关系与公开名片
94
+
95
+ ```ts
96
+ const state = subject.getOwnershipStatus();
97
+ console.log('本地关系状态', state.status, state.proof_id);
98
+ console.log('本地owner与类型', subject.getOwner(), subject.getType());
99
+
100
+ const published = await subjectStore.downloadAgentMd('subject.agentid.pub');
101
+ if (!published.ok) throw new Error(published.error.message);
102
+ console.log('文件与关系验签', published.data.verification);
103
+ ```
104
+
105
+ 按三个结果分别判断:
106
+
107
+ | 需要判断的结果 | 观察方式 | 含义 |
108
+ | --- | --- | --- |
109
+ | 双方是否已签署 | 本地`status === 'active'`,并核对双方AID及`proof_id` | 本端已保存完整关系;self-owner为subject单签 |
110
+ | owner代上传及通知是否结束 | owner侧的`agent_md_uploaded`、`agent_md_notified` | owner本地编排进度,不是subject同步回执 |
111
+ | subject是否已同步名片 | subject侧的`agent_md_synced`;公开名片的`verification` | 文件验签结果与ownership结果分别检查;完整公开关系为`ownership_status === 'complete'` |
112
+
113
+ `getOwner()`优先返回active关系,也可能返回pending等尚未释放的记录,因此仅有owner值不足以确认绑定完成。`getOwnershipStatus()`选择一条涉及当前AID的关系并优先active;owner管理多个subject时,它不返回全量列表,应用应同时核对目标subject。
114
+
115
+ 当前进度字段来自本地metadata,字段未出现通常表示该步骤尚未记录。完整proof可以先于托管和owner代上传公开;托管失败不会撤销双方已完成的签名关系。
116
+
117
+ ### 1.6 self-owner与解绑
118
+
119
+ self-owner在subject本地完成:
120
+
121
+ ```ts
122
+ await subject.bindOwner(subject.aid!);
123
+ ```
124
+
125
+ 该入口只生成subject签名、上传本端名片,不发送绑定申请、不托管identity,也不需要应用审批。`human`名片不允许声明owner,包括self-owner。
126
+
127
+ 外部owner释放关系:
128
+
129
+ ```ts
130
+ await owner.releaseOwnership('subject.agentid.pub');
131
+ ```
132
+
133
+ subject SDK验证原关系后自动rekey、保留名片业务内容、删除`owner`和`ownership_proof`、写入`ownership_release`并上传。subject侧最终为`status: released`、`release_status: released`,公开名片的关系验签状态为`released`。
134
+
135
+ 解绑方法返回的是释放消息发送结果。owner本地的`release_status: notified`表示已发起通知;当前没有释放完成的P2P回执,确认最终结果应查看subject状态或下载其公开名片。换owner时先完成释放,再重新绑定;subject没有单方解除入口。
136
+
137
+ 应用业务结束、后续编排已经完成时关闭客户端:
138
+
139
+ ```ts
140
+ await Promise.all([owner.close(), subject.close()]);
141
+ ```
142
+
143
+ ## 2. 应用需要使用的SDK方法
144
+
145
+ | TypeScript方法 | 调用方 | 返回与边界 |
146
+ | --- | --- | --- |
147
+ | `bindAid(subjectAid, options?)` | owner | 异步;创建owner声明并发送申请 |
148
+ | `bindOwner(ownerAid, options?)` | subject | 异步;创建subject声明;self-owner在本地完成 |
149
+ | `acceptOwnershipRequest(requestId, { extensions }?)` | 申请接收方 | 异步;只处理本端待审批申请,签署本端声明并推进后续流程 |
150
+ | `rejectOwnershipRequest(requestId)` | 申请接收方 | 异步;拒绝申请并发送`bind.reject` |
151
+ | `releaseOwnership(subjectAid)` | 原owner | 异步;要求本地active关系,发送释放声明 |
152
+ | `getOwner()` / `getType()` / `getOwnershipStatus()` | 双方 | 同步;读取本地摘要,排除identity、托管密码和下载地址 |
153
+
154
+ 绑定选项为`subjectType`、`requestId`、`extensions`,前两项也接受`subject_type`、`request_id`。默认类型为`agent`,未传请求ID时SDK生成ID;每次调用绑定方法都会创建新`proof_id`,复用`requestId`不构成整个绑定API的幂等保证。发送中断后的恢复应保留原数据目录,由SDK续跑原记录。
155
+
156
+ ## 3. SDK层面的绑定编排
157
+
158
+ ### 3.1 owner发起
159
+
160
+ ```mermaid
161
+ sequenceDiagram
162
+ participant OA as owner应用
163
+ participant O as owner SDK
164
+ participant M as 加密P2P
165
+ participant S as subject SDK
166
+ participant SA as subject应用
167
+ OA->>O: bindAid(subjectAid)
168
+ O->>O: 签署owner声明,持久化pending
169
+ O->>M: bind.request
170
+ M->>S: 解密后拦截并验证申请
171
+ S->>S: 保存待审批记录
172
+ S->>SA: ownership.request
173
+ alt 应用接受
174
+ SA->>S: acceptOwnershipRequest(request_id)
175
+ S->>S: 签署subject声明,持久化active
176
+ S->>M: bind.response
177
+ M->>O: 验证subject声明,持久化active
178
+ S->>S: 立即发布完整proof名片,之后独立尝试identity托管
179
+ else 应用拒绝
180
+ SA->>S: rejectOwnershipRequest(request_id)
181
+ S->>M: bind.reject
182
+ M->>O: 记录rejected
183
+ end
184
+ ```
185
+
186
+ ### 3.2 subject发起
187
+
188
+ ```mermaid
189
+ sequenceDiagram
190
+ participant SA as subject应用
191
+ participant S as subject SDK
192
+ participant N as subject Name Service
193
+ participant O as owner SDK
194
+ participant OA as owner应用
195
+ SA->>S: bindOwner(ownerAid)
196
+ S->>S: 签署subject声明,持久化pending
197
+ S->>N: 尝试上传不完整proof名片
198
+ S->>O: 加密P2P bind.request
199
+ O->>O: 验证并保存待审批记录
200
+ O->>OA: ownership.request
201
+ alt 应用接受
202
+ OA->>O: acceptOwnershipRequest(request_id)
203
+ O->>O: 签署owner声明,持久化active
204
+ O->>S: 加密P2P bind.response
205
+ S->>S: 验证并保存完整proof,标记active并立即发布名片
206
+ else 应用拒绝
207
+ OA->>O: rejectOwnershipRequest(request_id)
208
+ O->>S: 加密P2P bind.reject
209
+ S->>S: 记录rejected
210
+ end
211
+ ```
212
+
213
+ 双方分别签署自己的声明;`proof_id`和双方AID相同,`signed_at`和`extensions`可以不同。`ownership.request`是SDK本地应用事件,原始`aun.ownership.v1`控制消息由SDK消费。
214
+
215
+ ## 4. SDK自动托管、代上传和同步
216
+
217
+ 两个绑定方向在subject取得完整proof后立即发布关系名片,再独立尝试托管;发布和托管分别记录进度:
218
+
219
+ ```mermaid
220
+ sequenceDiagram
221
+ participant S as subject SDK
222
+ participant T as subject Storage
223
+ participant O as owner SDK
224
+ participant K as owner身份存储
225
+ participant N as subject Name Service
226
+ S->>N: subject立即尝试发布完整proof名片
227
+ Note over S,N: 发布失败保留pending上传,不阻止托管
228
+ S->>S: 打包identity,生成密码并加密
229
+ S->>T: 上传envelope,写owner的r ACL,申请下载票据
230
+ S->>O: 加密P2P escrow.ready
231
+ O->>T: 使用票据下载加密envelope
232
+ O->>O: 解密,校验subject身份与密钥
233
+ O->>K: 导入subject identity并加密保存私钥
234
+ O->>O: 用subject私钥签名片,用owner私钥签上传授权
235
+ O->>N: PUT /agent.md,携带owner授权头
236
+ N->>N: 验证完整proof、上传者与subject文件签名
237
+ N-->>O: 上传结果与ETag
238
+ O->>S: 加密P2P agent_md.updated
239
+ S->>N: 下载、验签并保存本地名片
240
+ ```
241
+
242
+ subject自行上传名片和identity托管分别尝试;一个步骤失败不会阻止另一项尝试。owner得到的是能代表subject签名的identity。名片内容签名者始终是subject,HTTP上传授权者可以是owner。
243
+
244
+ 当前SDK仅为该escrow对象写入owner读取ACL;其它业务目录的授权、备份策略与清理不属于这段自动编排。跨issuer下载使用资源所在域签发的票据;同issuer下载可携带当前access token。
245
+
246
+ ## 5. SDK自动解绑与中断恢复
247
+
248
+ ```mermaid
249
+ flowchart TD
250
+ A[原owner签署并发送release.request] --> B[subject验证sender、release和当前关系证据]
251
+ B --> C[持久化release_status为pending_rekey]
252
+ C --> D[恢复或完成rekey并载入新身份]
253
+ D --> E[进入pending_agent_md]
254
+ E --> F[比较本地与远端尾部签名时间,选择较新名片]
255
+ F --> G[移除owner和proof,保留release及业务内容]
256
+ G --> H[持久化pending_upload及待上传内容]
257
+ H --> I[用新subject证书签名并上传]
258
+ I --> J[上传成功,标记released]
259
+ ```
260
+
261
+ rekey阶段可能断开并重新连接;待处理记录和待上传名片跨重启保存。名片时间相同优先使用远端版本。若远端已经保存同一份有效release,SDK可直接收敛到released。
262
+
263
+ 绑定恢复遵循已有IM消息的异步处理方式:保存待发控制消息,重连后重发;待审批申请重新发布给应用;subject重试名片发布和托管;owner从本地身份存储恢复subject signer。若owner尚未获得材料,会重发自己的绑定响应,让subject重新发送托管通知。恢复依赖同一AID的数据目录及密钥保护配置。
264
+
265
+ ## 6. 实现与协议入口
266
+
267
+ - SDK移植、持久化与验收:[Ownership SDK实现指南](Ownership-SDK实现指南.md)。
268
+ - 消息schema、proof、agent.md和现有RPC:[Ownership协议定义](../protocol/Ownership协议定义.md)。
269
+ - 原专题与完整消息样例:[Ownership管理专题](Ownership管理专题.md)。
270
+ - 示例对应源码:[client.ts](../../ts/src/client.ts)、[aid-store.ts](../../ts/src/aid-store.ts)、[ownership-proof.ts](../../ts/src/ownership-proof.ts)、[agent-md.ts](../../ts/src/agent-md.ts)。
@@ -0,0 +1,300 @@
1
+ # Ownership 2.1 SDK 应用集成指南
2
+
3
+ 本文面向应用开发者,以当前工作区的 Node.js TypeScript SDK 为例,说明身份准备、发起关系操作、接入审批界面或自动策略、跟踪结果与断线恢复。协议依据为 [Ownership 协议定义 2.1](../protocol/Ownership协议定义2.1.md);编排契约见 [Ownership SDK 编排指南 2.1](Ownership-SDK编排指南2.1.md),实现边界见 [Ownership 2.1 详细设计](Ownership2.1详细设计.md)。
4
+
5
+ 需要实现或移植 SDK 内部机制时,查阅 [Ownership 2.1 SDK 开发与移植指南](Ownership2.1-SDK开发与移植指南.md);本文聚焦应用公有接口。
6
+
7
+ 本文使用当前 [包入口](../../ts/src/index.ts) 和 [AUNClient](../../ts/src/client.ts) 的公有 API。工作区包名为 `@agentunion/fastaun`、参考版本为 `0.5.19`,要求 Node.js `>=22.16.0`,见 [package.json](../../ts/package.json)。这些信息描述当前源码,不表示同版本 npm 包已经发布或包含本工作区的全部 2.1 实现。旧 `Ownership-SDK集成指南.md`、`Ownership-SDK实现指南.md` 属于 legacy;协议 3.0 不属于本文范围。
8
+
9
+ 兼容方向为新服务端兼容新旧 SDK 的既有身份认证、普通名片和通信入口,并保留旧 SDK 的 legacy owner 操作;新 SDK 的 2.1 关系操作不兼容旧服务端。Ownership 2.1 当前关系始终重新核对两份当前文件;旧 SDK 的旧格式关系由隔离的 Auth JSONL、operation ID 和 NS ownership_proof 兼容,不生成 2.1 双文件或共识,也不得覆盖已存现代声明。不把新 SDK 源码调用形态兼容作为本契约要求。
10
+
11
+ ## 1. 应用需要理解的关系边界
12
+
13
+ `group/org` 作为被管理的 `sub` 时使用自身生命周期:创建自动建立 owner,解散自动解除,专属转移强制 rekey,身份材料始终由当前 owner 持有;它们不适用本指南针对 `sub` 的绑定、释放、转移和审批流程。Group/Org 仍可按普通主体关系中的 owner 规则作为 `owner_aid`。将 Group/Org 作为 `sub` 调用任务 Facade 会 reject/抛出 `not_applicable`(`retryable=false`);对其调用 `checkOwnershipConsensus` 才会返回 `status/code=not_applicable` 的共识结果对象。名片必须含 owner,必须省略 ownership、ownership_proof、ownership_release,并由实体私钥主签、当前 owner 使用本人 token 上传,可选追加 owner 附签;完整格式见 [协议 §2.5](../protocol/Ownership协议定义2.1.md#25-grouporg-名片的实体主签与-owner-上传)。Group 入口见 [Group RPC Manual](09-group-rpc-manual.md#群组生命周期),Org 沿用专属 0.8 生命周期,不把组织成员双签解释为 Ownership 2.1。
14
+
15
+ 现代 Group/Org 文件的 `entity_cert_fingerprint` 与主签 `cert_fingerprint` 必须是相同的完整 `sha256:<64位小写hex>`,主块显式 `signer_aid=实体AID`;每个附签必须是当前 owner,存在就必须全验。只有 type=group、恰好一个签名块、未出现 entity_cert_fingerprint 且主块 signer_aid 缺省或等于群 AID 的文件才可走旧 Group 读取兼容;字段已出现但无效不能按旧格式放行,Org 没有此入口。
16
+
17
+ Ownership 是 `agent.md` 上叠加的可选关系属性。Ownership 关系无效或暂时不可确认,只限制依赖该关系的授权、绑定、释放、转移等操作;它本身不会使基础格式和外层签名有效的 `agent.md` 失效。普通读取、下载、基础验签及通信仍可继续。NS 兼容旧 SDK 不带 Ownership 专用 Header 的普通读写和旧格式名片上传;旧关系字段在正文更新时必须原样保留。新 SDK 新建关系或提交新格式时仍须执行当前 Ownership 规则,不能用旧客户端兼容入口绕过校验。
18
+
19
+ | 名称 | 应用中的含义 |
20
+ | --- | --- |
21
+ | `sub_aid` | 被管理身份;签署自己的 `agent.md`,以自己的认证身份提交到 NS。 |
22
+ | `owner_aid` | 绑定目标或当前/原 owner;签署、发布自己 Storage 中的 `owner.md`。 |
23
+ | `new_owner_aid` | 转移目标;独立签署、发布自己的目标 `owner.md`。 |
24
+ | NS | 以数据库事务和 CAS 持久化 sub 的权威 `agent.md` 与同步待办,根据该名片和 owner 的权威 `owner.md` 验证当前关系。 |
25
+ | Storage | 保存 owner 的权威 `owner.md`,以及 NS 异步同步的 sub 名片副本。 |
26
+
27
+ 每个参与身份都需要自己的密钥、证书和客户端。owner 权限不等于持有 sub 私钥,也不授予代签或代上传能力。owner 文件位于 `owner_aid:/sub_aids/{sub_aid}/owner.md`;sub 的权威名片位于 NS,`sub_aid:/agent.md` 是其 Storage 副本。
28
+
29
+ Ownership 2.1 关系事实只来自 sub 的权威 `agent.md` 与 owner 签署、保存在自己 Storage 中的权威 `owner.md`。`owner_aid` 是 `owner.md` 中的 owner 身份字段,不是独立文件或数据库关系记录。NS 的数据库事务只保证 `agent.md` 原文、CAS 更新与同步待办的原子性,不另存关系账本或验收证据表,不依赖 `ownership.journal`、独立关系日志或 reserve-confirm 恢复流程。SDK 本地任务数据库仅用于恢复本端编排任务,不是关系事实的替代来源。
30
+
31
+ 应用调用 Facade 表达意愿,SDK 通过普通加密 P2P 消息协调各端自己的文件操作,NS 验收结果决定关系。本指南的 2.1 编排不新增 ownership 专用 RPC,也不需要应用自行构造控制消息或调用内部文件方法。文件角色、上传身份及 owner 锁约束见 [协议第 1、2 节](../protocol/Ownership协议定义2.1.md#1-权威文档与-owner-锁)。
32
+
33
+ ## 2. 接入前提与能力检查
34
+
35
+ | 前提 | 接入要求与不足时的处理 |
36
+ | --- | --- |
37
+ | 独立身份 | 各参与端加载本身份可用的私钥和证书。`AIDStore.load()` 成功也可能只得到公钥证书,仍须检查 `isPrivateKeyValid()`。 |
38
+ | 初始名片 | NS 上已有 sub 自己签署、上传的初始 `agent.md`。可用 `AIDStore.downloadAgentMd(subAid)` 确认可读;真正的关系变更仍由 Facade 新鲜检查。不存在时会遇到 `unavailable`,不能以本地空白名片代替。 |
39
+ | NS 2.1 | 部署支持基于两份权威文件的 2.1 新鲜关系检查,以及名片和同步待办的原子 CAS。只读共识检查遇到不支持时返回 `unavailable`,其 `code` 可为 `unsupported_protocol`。 |
40
+ | Storage | 部署支持权威对象查询和完整文件原子发布;写入前核对起始完整原文、摘要和存在性,清理前核对当前 NS 和本任务完整原件。 |
41
+ | P2P 编排 | 参与端运行支持当前编排的 SDK。对端离线或不能处理请求时保持等待,不把超时、ACK 或投递成功当作批准。 |
42
+ | 持久任务存储 | 固定、可写、可恢复的数据目录;创建和更新任务必须能够原子保存。存储不可用或损坏时停止有副作用的编排。 |
43
+ | 可信根与当前证书状态 | 安全配置根证书,验证证书链、用途和当前撤销状态。TLS 校验与文件签名验证都需要成立。 |
44
+
45
+ `checkOwnershipConsensus()` 是当前关系的只读预检,不是全部服务能力的探测接口。尤其是无 owner 时,它不会验证尚未读取的 owner Storage 发布能力;部署能力仍需由服务配置和验收结果确认。
46
+
47
+ `AIDStore` 的配置参数是 `aunPath`、`encryptionSeed`、`slotId?`、`verifySsl?`、`rootCaPath?`、`debug?`,见 [AIDStore](../../ts/src/aid-store.ts)。生产应用应显式设置 `verifySsl: true`,通过可信部署渠道配置 `rootCaPath`;该路径用于 SDK 的 AUN 证书信任验证,不自动替代 Node.js HTTPS/TLS 自身的信任配置。私有 TLS 站点仍需正确配置 Node.js 的 TLS 信任,不能仅凭该路径就视为可信。不能用对端提供的任意根替换本地信任配置。服务发现及外部地址使用部署域名,例如 `ns.agentid.pub`、`st.agentid.pub`。
48
+
49
+ 默认数据根为用户目录的 `.aun`。当前本地存储在首选目录不可用时还可能回退到工作目录的 `.aun`;应用应事先确保配置的固定绝对目录可写,避免重启或工作目录变化后使用另一份数据。任务保存于 `{aunPath}/AIDs/{aid}/aun.db`,与该身份的密钥、证书、本地 secret store 和稳定设备信息一起保留。`slotId` 也应固定;它不是任务数据库的隔离目录。实际路径逻辑见 [LocalTokenStore](../../ts/src/keystore/local-token-store.ts) 和 [配置实现](../../ts/src/config.ts)。
50
+
51
+ `persistence_unavailable` 表示本地任务存储能力缺失、数据库恢复不可用、任务记录损坏或原子保存失败;远端 NS ETag、owner 原件或原 NS CAS 条件变化属于 `conflict`,不是本地持久化故障。它不是连接成功后就能忽略的提示;Facade 可抛出该错误,恢复也会停止。只读共识检查不依赖本地任务存储,不能用其成功证明任务可持久化。
52
+
53
+ ## 3. 最小 TypeScript 接入
54
+
55
+ ### 3.1 装载存量身份
56
+
57
+ 以下 `appConfig` 由应用自行读取,类型为 `{ aunPath: string; encryptionSeed: string; rootCaPath: string }`。`aunPath` 为固定持久绝对目录,`encryptionSeed` 从应用自己的秘密配置提供;这些不是 `AUNClient` 构造参数。
58
+
59
+ ```ts
60
+ import { AIDStore, AUNClient } from '@agentunion/fastaun';
61
+ const store = new AIDStore({
62
+ aunPath: appConfig.aunPath, encryptionSeed: appConfig.encryptionSeed,
63
+ rootCaPath: appConfig.rootCaPath, verifySsl: true, slotId: 'ownership-app',
64
+ });
65
+ const loaded = store.load('helper.agentid.pub');
66
+ if (!loaded.ok) throw new Error(loaded.error.message);
67
+ if (!loaded.data.aid.isPrivateKeyValid()) throw new Error('本身份私钥不可用');
68
+ const client = new AUNClient(loaded.data.aid);
69
+ ```
70
+
71
+ 构造函数接收 `AID` 对象或无参,不接收 AID 字符串、配置对象或其它身份的凭据。需要延后装载时,可在无身份或已关闭状态调用 `loadIdentity(aid)`;无参构造会先使用默认数据配置,本例直接传入已装载的 AID,使客户端沿用其 `aunPath`、设备、slot、TLS 和可信根配置。连接选项传给 `connect()`,不是构造函数。
72
+
73
+ ### 3.2 首次注册的独立分支
74
+
75
+ 没有本地身份时,先通过同一个 `AIDStore` 注册,再执行上述装载流程。下面是首次注册分支,不是每次启动都执行的步骤:
76
+
77
+ ```ts
78
+ const registered = await store.register('helper.agentid.pub', {
79
+ type: 'agent', owner: 'owner.agentid.pub',
80
+ });
81
+ if (!registered.ok) throw new Error(registered.error.message);
82
+ ```
83
+
84
+ `register()` 返回 `Result<{ registered: true }>`,并尝试以本身份条件创建初始名片。`type: 'agent'` 的 `owner` 可省略;省略时只初始化普通 `agent.md`,不保存 Ownership 关系意图。有 owner 时保存固定 `operation_id` 的 owner 注册意图;初始名片不直接写入 owner 关系,首次连接后 SDK 用原意图继续绑定,owner 仍须审批。应用需确认初始名片已可用,不能把 `registered: true` 当作关系建立完成,也不能再调用绑定发起接口来“继续注册”。`type: 'human'` 禁止提供 owner,`group/org` 要求当前 owner 并沿用专属生命周期。注册与恢复见 [AIDStore.register](../../ts/src/aid-store.ts) 和 [设计第 7.1 节](Ownership2.1详细设计.md#71-七个-facade-与内部复用)。
85
+
86
+ ### 3.3 先订阅,再连接
87
+
88
+ 事件处理器类型是 `(payload) => void | Promise<void>`,直接收到载荷,没有 `event.data` 包装。以下 `showApproval`、`updateOwnershipView` 为应用自实现函数;签名分别为 `showApproval(payload: Parameters<EventHandler>[0]): void`、`updateOwnershipView(event: string, payload: Parameters<EventHandler>[0]): void | Promise<void>`。应用负责按第 5 节字段解析、保存和展示载荷。
89
+
90
+ ```ts
91
+ import type { EventHandler } from '@agentunion/fastaun';
92
+ const onRequest: EventHandler = payload => showApproval(payload);
93
+ client.on('ownership.request', onRequest);
94
+ const events = ['ownership.action_required', 'ownership.progress', 'ownership.completed',
95
+ 'ownership.rejected', 'ownership.stopped', 'ownership.error'];
96
+ for (const event of events) client.on(event, payload => updateOwnershipView(event, payload));
97
+ await client.connect({ auto_reconnect: true });
98
+ ```
99
+
100
+ `connect()` 使用已装载身份完成认证。连接及重连成功后会在后台触发注册意图和 Ownership 任务恢复,`await connect()` 返回不代表所有恢复任务完成。连接前订阅可接到恢复中的审批或终局事件;页面卸载时可对 `on()` 返回的 `Subscription` 调用 `unsubscribe()`。接线见 [AUNClient](../../ts/src/client.ts) 和 [事件类型](../../ts/src/events.ts)。
101
+
102
+ ### 3.4 通用签验与多签名片
103
+
104
+ 应用通过 `AIDStore.sign/verify` 使用通用签验,TS/JS 两者均须 await,返回 `Promise<Result>`。默认 `format: 'raw'` 生成/验证 detached Base64 签名;`format: 'document'` 返回签后全文与签名列表,verify 返回 valid、status、payload 和逐块 signatures。先检查外层 ok,再判断验签 valid;数学失败保留全部逐块结果,resolver 操作异常是外层 error。详细参数及四语言命名见 [API 手册](06-API手册.md#通用-sign--verify)。
105
+
106
+ 输入默认是文本,不猜测路径或识别 file://;读文件须显式 inputType: 'file'(Python input_type),原地签写还须 document + inPlace: true(Python in_place),成功后才写回。raw 文件按任意原字节签验,字符串和 document 严格 UTF-8;浏览器 File/Blob 只读,FileSystemFileHandle 才能原地写。verify 默认离线加载本地公钥/证书,无需私钥;历史或远端证书由应用显式提供可信 certificateResolver,不能把通用数学验签当作证书链、当前生命周期或 owner 授权检查,既有 downloadAgentMd 仍保留原远程验证流程。
107
+
108
+ 需要附签时对完整已签原文使用 document + append: true;后块签正文与全部前序完整块的原始 prefix,只有已有签名链的末字节非 CR/LF 时才补 LF,无旧块按首签要求非空正文以换行结束。TAG 仅字面标签、附签有则全验;返回列表只表示实际存在的签名,不能检测末端删签。agent.md、owner.md 与公共门面复用同一内部 core,业务仍单独校验 Schema、主签身份和资源授权;普通 agent.md/owner.md 主块不输出且不接受 signer_aid。sign 本身不发布文件,名片发布仍使用 uploadAgentMd,owner.md 仍由关系 Facade 管理,见 [协议 §2.4/§2.5](../protocol/Ownership协议定义2.1.md#24-文件签名)。
109
+
110
+ 新 SDK 的每个 NS GET/HEAD/PUT(含 fallback、fresh、重试)携带 X-AUN-Signature-Format: multi-v1 获取完整多签。无头旧客户端的多签读取只返回正文与首块,单签保持原 raw;HTTP 的 ETag、304 与缓存按表示区分,服务完整存储不变,应用应保留该表示原 ETag 作为条件。实体 fresh GET 还同时携带 X-AUN-Ownership-Check: 1 与 Cache-Control: no-cache,绕过 LRU 全块新鲜验证,仍为 not_applicable,不进入通用关系账本。
111
+
112
+ ## 4. 七个 Facade 的参数、角色与结果
113
+
114
+ 六个任务/审批方法返回 `Promise<OwnershipTaskResult>`;共识方法返回独立的 `Promise<OwnershipConsensusResult>`。方法名的 `Owneraid`、`Subaid` 大小写需按下面原样使用。
115
+
116
+ | 方法及参数 | 本端调用角色 | 结果与行为 |
117
+ | --- | --- | --- |
118
+ | `bindOwneraid(ownerAid: string)` | sub | 请求绑定指定 owner;发起即表达 sub 意愿,owner 收到审批请求。 |
119
+ | `bindSubaid(subAid: string)` | owner | 请求管理指定 sub;sub 收到审批请求。 |
120
+ | `releaseSubaid(subAid: string)` | 当前/原 owner | 发布释放并等待 NS 确认;不要求 sub 审批或在线。 |
121
+ | `transferSubaid(subAid: string, newOwnerAid: string)` | 当前/原 owner | 请求 sub 和新 owner 审批后转移;新 owner 必须不同于原 owner。 |
122
+ | `acceptOwnershipRequest(operationId: string)` | 已验证请求的本端接收方 | 批准已有绑定或转移任务;关联原任务,不创建新任务。 |
123
+ | `rejectOwnershipRequest(operationId: string, reason?: string)` | 已验证请求的本端接收方 | 拒绝已有绑定或转移任务;`reason` 是可选字符串。 |
124
+ | `checkOwnershipConsensus(subAid?: string)` | 检查方 | 只读检查当前关系;省略参数时检查本端 AID,owner 查询自己管理的身份时应明确传入 sub。 |
125
+
126
+ 任务结果包含 `operation_id`、`operation`(`bind`/`release`/`transfer`)、`sub_aid`、`owner_aid`、起始 `base_relation_version`、目标 `target_relation_version`、`status` 和 `step`;转移另有 `new_owner_aid`。`status` 为 `pending`、`completed`、`rejected`、`stopped` 或 `error`;`step` 是当前本端阶段字符串,不是共识枚举。`code`、`reason`、`retryable` 是可选错误信息。
127
+
128
+ `pending` 可保留等待恢复的工作;`rejected`、`stopped`、`error` 会停止常规任务推进,不能假定重连后都能继续。`completed` 后仍可能为字段清理或旧文件清理发布 `ownership.error`;应用应根据任务状态和当前共识展示清理失败,不能把既成关系改回未完成。
129
+
130
+ 独立绑定示例适用于已准备好的存量 sub,且没有正在续跑的 owner 注册意图。`saveBusinessTask(task: OwnershipTaskResult): Promise<void>` 由应用实现,持久保存业务记录与 SDK 任务 ID 的对应关系:
131
+
132
+ ```ts
133
+ import type { OwnershipTaskResult } from '@agentunion/fastaun';
134
+ const task: OwnershipTaskResult = await client.bindOwneraid('owner.agentid.pub');
135
+ await saveBusinessTask(task);
136
+ ```
137
+
138
+ 不要只保存“已点击绑定”:保存 `operation_id`、参与 AID、起始/目标版本、最后的 `status`、`step` 和错误信息,便于页面重载后继续展示同一业务任务。任务结果可带等待或错误信息,Promise 正常返回也不一定是 `completed`。类型定义见 [OwnershipTaskResult](../../ts/src/ownership-workflow.ts),包入口已公开该类型。
139
+
140
+ 四个发起 Facade 会先匹配本端相同的进行中意图;匹配本端身份、发起方、操作、全部参与方及起始/目标关系版本时复用原 `operation_id`,没有匹配任务时才生成新的 UUID。应用收到 ready 消息、超时或断线后应让 SDK 恢复原任务,不能通过更改参数或伪造 `operation_id` 冒充原任务重试。
141
+
142
+ 首次权威预检抛错时可能尚未创建任务,应用不一定拿到 `operation_id`;其它阶段抛错也不保证任务或副作用不存在。应用应结合已保存的业务记录、已收到的事件和当前权威关系确认阶段,不能以“没有返回 ID”为由盲目重复发起。
143
+
144
+ ## 5. 审批与本地事件接入 UI
145
+
146
+ 本地事件直接携带任务结果字段,并增加以下信息。它们属于本端 SDK 通知,不是服务端 `event/...`,也不作为 P2P 消息再次发送。
147
+
148
+ | 载荷字段 | UI/策略用途 |
149
+ | --- | --- |
150
+ | `operation_id`、操作和参与 AID | 关联业务任务,展示被管理身份、原 owner、转移目标。 |
151
+ | `requester_aid` | 仅 `ownership.request` 附带,经消息层确认的发起方;不能从任意聊天文本自报字段推导审批身份。 |
152
+ | `local_roles` | 本端承担的 `owner`、`sub`、`new_owner` 角色数组;同一 AID 可同时承担多个角色。当前实现为各 Ownership 本地事件附带它。 |
153
+ | `base_relation_version`、`target_relation_version` | 本次固定审批上下文,不允许 UI 在批准时替换目标。 |
154
+ | `relation_version` | SDK 已核验目标时附带的版本;未核验时可缺省,不能用它替代新鲜共识。 |
155
+ | `status`、`step`、`code?`、`reason?`、`retryable?` | 当前任务及错误展示;错误字段按实际存在处理。 |
156
+
157
+ | 事件 | 应用处理 |
158
+ | --- | --- |
159
+ | `ownership.request` | 显示同意/拒绝或交给明确的自动策略;策略未决定时保持待审批。 |
160
+ | `ownership.action_required` | 提示释放后 sub 的名片清理缺少应用明确授权;处理见第 6.2 节。 |
161
+ | `ownership.progress` | 更新本端进度,不宣布关系成立。 |
162
+ | `ownership.completed` | 记录本任务目标已核验;清理、副本同步和凭据交接另行跟踪。 |
163
+ | `ownership.rejected` | 本次审批拒绝,不回滚已验收的历史关系。 |
164
+ | `ownership.stopped` | 本次流程不再推进;不是关系解锁通知。 |
165
+ | `ownership.error` | 展示错误和可重试提示,核对载荷中的任务状态;已完成关系的后续清理错误单独展示。 |
166
+
167
+ `EventHandler` 是通用载荷类型,不能把回调参数直接当作一个已声明的专用请求类型。应用的 `showApproval` 应解析本端请求字段并保存 `operation_id`,再产生自己的界面决定。下面的 `appApproval` 由该 UI 或自动策略提供,类型为 `{ operation_id: string; accept: boolean; reason?: string }`;`showOwnershipError(code: string, retryable: boolean): void` 也是应用自实现函数。
168
+
169
+ ```ts
170
+ import { AUNError } from '@agentunion/fastaun';
171
+ try {
172
+ const result = appApproval.accept
173
+ ? await client.acceptOwnershipRequest(appApproval.operation_id)
174
+ : await client.rejectOwnershipRequest(appApproval.operation_id, appApproval.reason);
175
+ await saveBusinessTask(result);
176
+ } catch (error) {
177
+ if (error instanceof AUNError) showOwnershipError(error.stringCode, error.retryable);
178
+ else throw error;
179
+ }
180
+ ```
181
+
182
+ 同一批准或拒绝可按原 ID 幂等处理,已经持久保存的决定不能改成相反决定。发起方无需再批准自己;审批方法只用于本端已有、已验证的绑定或转移请求。无界面应用也必须明确作出同意或拒绝,SDK 不因无人响应而默认批准。
183
+
184
+ 恢复可能再次发出待审批请求。UI 按 `operation_id`、事件名和 `step` 幂等更新,已保存的决定不重新询问或改变。不要把所有历史事件都会重放当作前提:应用自己的业务记录和最后进度仍需持久保存。载荷与接线依据见 [编排指南第 2.6 节](Ownership-SDK编排指南2.1.md#26-本地事件与完成依据) 和 [当前 emit 实现](../../ts/src/ownership-workflow.ts)。
185
+
186
+ ## 6. 关系操作流程
187
+
188
+ ### 6.1 绑定:双方都可发起
189
+
190
+ | 发起方 | 入口 | 接收方审批后的共同顺序 |
191
+ | --- | --- | --- |
192
+ | sub | `subClient.bindOwneraid(ownerAid)` | owner 发布自己的 `owner.md` → sub 自签提交自己的 `agent.md` → NS 验收目标 owner 与版本 → 各端新鲜核验完成。 |
193
+ | owner | `ownerClient.bindSubaid(subAid)` | sub 批准后,按同一文件顺序推进。 |
194
+
195
+ 绑定只从当前两份权威材料确认无锁时开始,目标版本为 `agent.md` 当前可见声明版本加一;名片无声明时基数为 `0`,目标为 `1`。已有稳定 owner 锁时,sub 不能通过普通名片更新清除或更换 owner。应用也不能因双方私下同意就跳过 NS 验收。
196
+
197
+ 释放后再绑定同一 owner,若 sub 的 `agent.md` 仍保留旧声明,须先由 sub 完成已有字段清理,再发布新的 owner declare;SDK 在创建任务或产生副作用前以 `conflict`/`action_required` 提示,避免新 declare 覆盖唯一释放依据。绑定不同 owner 仍可使用当前可见版本 `v+1`;已清理时默认从 `1` 开始。
198
+
199
+ ### 6.2 释放:原 owner 发起,sub 可以离线
200
+
201
+ 原 owner 调用 `releaseSubaid(subAid)`,SDK 发布当前声明版本 `v` 的 release 文件;释放任务的起始、目标及历史 verified 版本均为 `v`,NS 不另存释放状态或递增版本。sub 不必在线;NS 根据 `agent.md` 的当前声明与有效 release 文件,或该 owner 路径的权威不存在结果,动态确认 `released`。服务或验证依赖不可用不能当作删除。sub 的旧名片字段可暂时保留,原 owner 可凭新鲜 `released/v`,或本任务 release 原件与当前 owner.md 全文、hash、当前有效证书精确匹配后确认的真实 `unbound/0` 完成;响应丢失时重新读取当前完整文件确认。实际完成证据保留真实状态和版本;权威删除不是取消任务。
202
+
203
+ sub 收到 release 通知时,可使用本人明确 accept、含 sub 角色,且本人已签 agent 的 owner、sub 与被释放完整 statement(含 declaration_id、版本)完全匹配的原绑定/转移记录自动自签清理,即使原任务因发布响应丢失仍 pending;转移历史匹配其目标 owner。无控制消息时,仅已完成历史任务的恢复路径触发自动清理,即使没有收到 relation.confirmed,也须新鲜核验权威释放事实。清理原件及原 CAS 单独保存,历史 completed 及完成证据保持。响应丢失后复用清理原件与条件,原文、ETag及已知提交 ETag 已对应原提交时只观察完成,字段已清空时不再签名或 PUT。缺少该授权且旧字段仍在时,发布 `ownership.action_required`,本端清理任务保持等待。
204
+
205
+ 释放清理不能调用 `acceptOwnershipRequest`/`rejectOwnershipRequest`,这两个接口会拒绝 release 任务。应用明确决定清理后,由 sub 用自己的身份通过现有 `AIDStore.uploadAgentMd(subAid, content)` 自签上传清除旧 `owner`、`ownership` 的名片,遵守当前 NS 条件与代际,不能指定其它上传身份或覆盖后续关系。新鲜有效名片的关系字段已清空时,SDK 仅在本任务持久清理原件、摘要、原 CAS,或本人明确 accept 的匹配原 bind/transfer.release_cleanup,与当前 NS 原文、摘要、ETag及已知提交 ETag 精确对应后观察完成;空字段本身不证明该任务完成,也不补造 sub 的清理同意或历史条件。
206
+
207
+ 已完成的历史绑定/转移或释放任务保持历史完成,但当前关系必须从两份权威材料重新判断:旧声明仍在且释放依据有效时为 `released`,名片清理后为 `unbound`、版本 `0`。NS 不保留释放终局或历史版本上界,材料不可确认时不得沿用历史释放结果作当前授权。详细释放与清理规则见 [编排指南第 2.4 节](Ownership-SDK编排指南2.1.md#24-应用层-facade编排审批与共识检查) 和 [协议第 4.2 节](../protocol/Ownership协议定义2.1.md#42-解绑)。
208
+
209
+ ### 6.3 三方转移
210
+
211
+ 原 owner 调用 `transferSubaid(subAid, newOwnerAid)`。sub 与新 owner 分别接到同一任务的审批请求,两者可任意先后决定;全部同意后,原 owner 发布指定新 owner 的转移授权,新 owner 发布目标 `owner.md`,sub 自签提交目标 `agent.md`,NS 从旧版本 `v` 直接切换到 `v+1`。
212
+
213
+ 任一尚待决定的接收方拒绝,审批阶段结束并保留原关系。批准消息本身不能完成转移;迟到拒绝不能改变同一审批方已保存的同意或已提交的关系。转移授权具有固定期限,恢复不能刷新期限或换目标,过期或版本冲突后停止旧流程。应用不得把转移失败自动改为先释放再绑定;该做法会改变授权条件和关系连续性。转移验收见 [协议第 4.3 节](../protocol/Ownership协议定义2.1.md#43-transfer_owner)。
214
+
215
+ ### 6.4 自拥有与角色重合
216
+
217
+ | 情形 | 本端决定与文件要求 |
218
+ | --- | --- |
219
+ | 建立 self-owner | sub 调用 `bindOwneraid(自己的 AID)`,或 owner 角色调用 `bindSubaid(自己的 AID)`;一次发起覆盖本端两个角色,仍分别签署、提交双文件。 |
220
+ | 外部 owner → self-owner | 原外部 owner 发起转移,目标为 sub;sub 同时承担 `sub` 和 `new_owner`,一个审批决定覆盖两角色,先发布自己的 owner 文件再提交名片。 |
221
+ | self-owner → 外部 owner | 同一 AID 兼任原 owner 与 sub,发起意愿覆盖这两个本端角色,外部新 owner 仍须审批。 |
222
+
223
+ SDK 合并同一接收 AID 的请求,不给自己发送 P2P。self-owner 仍要验证双文件并建立锁;`human` 不能声明 owner,包括自拥有;SDK 在任务、消息和文件副作用前拒绝此绑定。原 owner 与新 owner 相同不是有效转移。业务若要求外部管理方,还须检查 `owner_aid != sub_aid`,不能仅凭 self-owner 的 `consensus` 满足该要求。参见 [协议第 4.5 节](../protocol/Ownership协议定义2.1.md#45-self-owner-的建立解绑与转移)。
224
+
225
+ ## 7. 任务完成与当前共识六态
226
+
227
+ 任务状态回答“这一个本端业务任务推进到哪里”,共识状态回答“当前两份权威材料证明什么关系”。普通主体适用下表六态;Group/Org 作为 `sub` 调用共识检查时返回特殊 `status/code=not_applicable`、`retryable=false`,不属于六态。P2P 投递成功、ACK、对端 `relation.confirmed` 提示或本地阶段标记都不是任务完成证据。绑定/转移的完成要求新鲜 NS 目标 owner、目标版本与本任务文件材料匹配;原 owner 必须有本任务已保存的转移授权,接收方固定首次验证授权的全文摘要及实际期限,不接受恢复时换字节或延期;释放完成要求新鲜 `released/v`,或按本任务原件严格关联的真实 `unbound/0`,任务起始、目标及历史 verified 版本仍为 `v`;历史完成记录不替代之后的当前关系查询。
228
+
229
+ ```ts
230
+ import type { OwnershipConsensusResult } from '@agentunion/fastaun';
231
+ const consensus: OwnershipConsensusResult = await client.checkOwnershipConsensus('helper.agentid.pub');
232
+ showConsensus(consensus);
233
+ ```
234
+
235
+ `showConsensus(result: OwnershipConsensusResult): void` 为应用自实现展示函数。结果包含 `status`、`sub_aid`、`owner_aid`(可为 null)、`relation_version`、`lock`、`agent_md_etag`、`agent_md_sha256`、`owner_md_sha256`,以及可选 `code`、`reason`、`retryable`。当 `status` 不是 `consensus` 或 `released` 时,未取得的权威观察字段可能为 null、空值或 SDK 使用的占位值(例如 `0`、`unlocked`);它们不表示实际观察到对应版本、锁或文件证据。应用必须先判断 `status`,任何结果字段本身都不能单独作为授权证据。定义见 [OwnershipConsensusResult](../../ts/src/ownership-v21.ts)。
236
+
237
+ | 共识状态 | 应用含义 |
238
+ | --- | --- |
239
+ | `consensus` | 当前未释放关系的身份、版本和双方完整文件签名匹配;执行端仍需认证调用者并核对业务权限范围。 |
240
+ | `released` | `agent.md` 仍有当前声明,但对应 `owner.md` 为有效 release 或已权威确认不存在;版本仍为该声明的 `v`,旧 owner 不再据此获权。 |
241
+ | `unbound` | 新鲜有效的权威名片没有当前关系声明,版本为 `0`;释放后字段清理也属于此态。解析失败、服务不可用或不完整观察不能推断无关系,此态也不证明某个 SDK 任务已结束或对端从未准备文件。 |
242
+ | `single_sided` | 仅一方准备或声明,稳定关系尚未成立。 |
243
+ | `invalid` | 字段、路径、角色、版本或签名无效,不能授予 owner 权限。 |
244
+ | `unavailable` | 当前 NS、Storage 或证书事实不能确认;保留最后已确认状态用于展示,不将未知当作解绑或授权。 |
245
+
246
+ 公开共识方法只有 sub 参数,不能枚举全网独立 owner 声明;NS 尚无 owner 且检查器没有目标上下文时,owner 单方已准备仍可能显示 `unbound`。该边界不能被 UI 用来推断某个绑定任务已取消。
247
+
248
+ 四 SDK 普通名片下载的 `verification.ownership_status` 仍是 legacy proof 展示字段,不是 2.1 授权结果。文件签名有效或旧展示状态为 complete 不能证明 2.1 共识;该展示字段对 2.1 名片显示不完整或其他旧状态也不能代替当前关系检查。应用使用 `checkOwnershipConsensus(subAid)` 获取 2.1 新鲜结果。
249
+
250
+ 关系完成、sub 字段清理、旧 owner 文件条件清理、NS 向 Storage 同步名片副本、应用凭据交接应分别展示。Storage 副本尚未同步不否定 NS 已完成的验收;反过来,本地或 Storage 上的旧名片也不能覆盖当前两份权威材料的共识。
251
+
252
+ 敏感业务在执行时由执行端核对当前 owner、sub、关系版本、权限范围和新鲜共识,并保存授权证据;UI 布尔值、历史完成事件和旧 token 不替代该校验。若业务使用 token/ACL,应把它们绑定到完整关系声明及其版本,并新鲜检查释放、转移后的有效性;清理后重新绑定可能再次使用版本 `1`,版本号不能单独识别关系。完整授权边界见 [协议第 6 节](../protocol/Ownership协议定义2.1.md#6-共识审计与安全边界)。
253
+
254
+ ## 8. 断线与重启恢复
255
+
256
+ 1. 启动时恢复原 `aunPath`、密钥解密配置、稳定设备和 slot,装载同一身份,先注册事件处理器再连接。
257
+ 2. SDK 从自己的持久任务继续审批、已签文件和待发送通知;请求重发和响应丢失的恢复复用原字节与原提交条件。恢复先核对权威关系和本任务证据,旧任务不能覆盖后续代际。
258
+ 3. 应用从自己的数据库恢复业务记录与 `operation_id`,幂等更新 UI。待审批请求可再次通知;已经保存的决定不重新作相反选择。
259
+ 4. 已合法完成的历史任务可以保留 `completed`,即使当前关系已被后续释放或转移;当前状态另调 `checkOwnershipConsensus(subAid)` 获取。
260
+
261
+ 当前七 Facade 没有公开“按 operation_id 查询任务”、取消任务或强制解锁接口。`getOwnershipStatus()`/`getOwner()` 读取旧 metadata,不是 2.1 任务查询或新鲜共识;cross-sdk 测试 agent 的私有存储查询也不是应用 API。因此业务层必须保存自己的任务关联和最后进度,不能依赖私有 `_tokenStore` 重建 UI。真实恢复触发点见 [AUNClient](../../ts/src/client.ts),任务恢复实现见 [OwnershipWorkflow](../../ts/src/ownership-workflow.ts)。
262
+
263
+ 重复发起相同进行中操作会复用原 `operation_id`、审批、签名字节、提交条件和授权期限;匹配要求本端身份、发起方、操作、全部参与方及起始/目标关系版本一致。同代际不同进行中意图返回 conflict,不产生第二任务。拒绝、停止、不可重试 error 不复活;后续代际的新合法操作使用新任务,历史 completed 不仅凭参数相同复用。不要删除任务数据库、清除审批记录、删除 `owner.md` 或刷新条件来制造“恢复成功”;删除 owner 的权威文件本身可能导致释放,含义不是取消任务。
264
+
265
+ Group/Org 名片失败稿及 pending 保留实体命名空间中的完整多签原文、原 CAS、固定 owner 和实体证书指纹,由应用显式重试,post-connect/重连不隐式 PUT。重试先验证完整原件及当前 owner、状态和证书代际,原条件完整且同代际原文/ETag 已确认提交时只观察完成。转移、rekey 或解散后停止旧代际待办,不更换身份、指纹或条件重签。取消实体 V2 授权后,不再保存、刷新或检查其额外授权及过期窗口;普通文件签名与当前证书检查保留。专属 create/transfer 自身 checkpoint 恢复机制不变。
266
+
267
+ ## 9. 错误处理与安全降级
268
+
269
+ 错误有三种入口:Facade 抛出异常;任务结果/本地事件附带错误;共识返回 `invalid` 或 `unavailable`。抛出的 `AUNError.code` 是数字 RPC 错误码,Ownership 字符串码读取 `error.stringCode`,是否可重试读取错误实例的 `error.retryable`;正常返回的任务或共识结果则读取其 `code`、`reason`、`retryable`。
270
+
271
+ | 字符串码或状态 | 应用处理 |
272
+ | --- | --- |
273
+ | `persistence_unavailable` | 停止有副作用的编排,恢复原持久存储能力;不以新任务替代损坏的审批历史。 |
274
+ | `unsupported_protocol` | 暂停 2.1 变更并核对 SDK/服务能力;不回落到 legacy 代理流程。 |
275
+ | `owner_locked` | 当前关系已有锁;按当前 owner 的释放或转移流程处理。 |
276
+ | `conflict` | NS ETag、owner 原件、原 NS CAS 条件、版本、目标或审批已变化;停止旧目标并重新核对权威事实,不自动换 ETag 或起始 owner 原件。 |
277
+ | `forbidden` | 调用角色、身份或审批阶段不允许;不更换凭据冒用另一方。 |
278
+ | `operation_not_found` | 本端没有该 ID 的请求;确认身份、持久目录及 UI 关联,不由审批 API 创建任务。 |
279
+ | `invalid` | 输入、签名、证书或材料确定无效;已有任务为不可重试 error,不将验签失败当成服务不可用或同意。 |
280
+ | `unavailable` | 服务、网络或依赖不可用,包括权威元数据、正文摘要不一致及 Storage Base64 传输封装损坏;已有任务保持 pending 并可重试,首次权威预检失败不创建任务。摘要匹配后确定非法的 UTF-8、文件字段或签名归 invalid。初始名片缺失或当前证书事实无法确认均须按原因处理。 |
281
+
282
+ 输入格式校验也可能抛出普通 `ValidationError`,其 `stringCode` 不一定已填;不要靠字符串码穷举替代正常异常处理。`retryable` 只提示可以恢复验证,不授权换目标、刷新期限或再发起一个新的操作。服务状态未知时,普通认证和通信可按各自能力继续,依赖 owner 权限的敏感操作须暂停。
283
+
284
+ 等审批、等材料及缺少 2.1 能力同样保持 pending;版本替代、目标改变、授权过期或原条件失效为 stopped;明确拒绝为 rejected,完整目标确认才为 completed。决定停止前先核验目标是否已提交;completed 后通知或清理失败只记录错误和待办。本地任务数据库写入/CAS、租约或持久化损坏返回 `persistence_unavailable`,保持原存储状态并停止副作用;远端 NS ETag、owner 原件或原 NS CAS 条件变化归为 `conflict`。三个协议时间字段采用 `1..9007199254740991` 的十进制正整数;范围内仍执行证书、当前时钟和授权未过期校验,重试不延期。
285
+
286
+ ## 10. 可选托管与旧接口迁移
287
+
288
+ 托管是应用显式启用的独立能力,不是绑定、释放或转移的前提。即使应用保存身份密文,两份关系文件仍由相应身份自己签署、上传。原 owner 曾能解密 sub 私钥时,关系转移不会自动撤销它掌握的凭据、续签或恢复能力;应用需独立确认凭据隔离,并将该交接进度与 NS 关系结果分开。
289
+
290
+ | 旧入口/判断 | 当前接入方式 |
291
+ | --- | --- |
292
+ | `bindOwner(...)`/`bind_owner(...)` | sub 使用 `bindOwneraid(ownerAid)`,owner 处理本端审批。 |
293
+ | `bindAid(...)`/`bind_aid(...)` | owner 使用 `bindSubaid(subAid)`,sub 明确审批。 |
294
+ | `releaseOwnership(...)`/`release_ownership(...)` | 当前 owner 使用 `releaseSubaid(subAid)`。 |
295
+ | 旧 `ownership_proof`、`proof.complete`、metadata owner | 改用当前双文件和新鲜 `checkOwnershipConsensus`;旧材料不是 2.1 共识证据。 |
296
+ | 旧代签、代上传、默认托管或自动 rekey 流程 | 按独立身份、明确审批及应用自己的可选凭据交接接入。 |
297
+
298
+ 当前这些 legacy 发起方法会抛出 `unsupported_protocol`,不是新接口的兼容别名。更换调用名称也不等于存量旧关系已经迁入 2.1;旧关系缺少可验证的当前关系事实或材料时保持原保护,迁入条件与双方重新签署需按明确方案处理,不能清空旧关系强行初始化。兼容边界见 [设计第 9 节](Ownership2.1详细设计.md#9-降级旧版及审计)。
299
+
300
+ 当前实现的实际验证与限制简要查阅 [TDD 账本第 13.4 节](Ownership2.1-TDD分阶段实施计划.md#134-测试与失败续跑账本)、[第 13.6 节四 SDK 一致性检查点](Ownership2.1-TDD分阶段实施计划.md#136-四-sdk-一致性检查点) 和 [第 13.7 节复审修复验收](Ownership2.1-TDD分阶段实施计划.md#137-2026-10-11-本轮复审修复验收)。本指南的短示例按当前 TypeScript 源码核对;本地类型成立不能替代服务部署、跨端通信或真实恢复验收。