@agentunion/fastaun 0.4.12 → 0.5.0

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 +488 -366
  2. package/_packed_docs/CHANGELOG.md +488 -366
  3. package/_packed_docs/INDEX.md +111 -53
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +43 -29
  5. package/_packed_docs/agent.md/SCHEMA.md +2 -0
  6. package/_packed_docs/agent.md/examples/codeagent-claudecode.md +2 -0
  7. package/_packed_docs/agent.md/examples/human-developer.md +2 -0
  8. package/_packed_docs/agent.md/examples/openclaw-lobster.md +2 -0
  9. package/_packed_docs/agent.md/examples/signed-openclaw-lobster.md +2 -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 +2 -0
  11. package/_packed_docs/cli/AUN-CLI/350/256/276/350/256/241/346/226/207/346/241/243.md +265 -686
  12. package/_packed_docs/collab-gateway-boundary-test-report.md +164 -0
  13. package/_packed_docs/design/2026-05-22-aun-rpc-trace-enhancement.md +2 -0
  14. package/_packed_docs/design/AUNClient/346/213/206/345/210/206/351/207/215/346/236/204/346/211/247/350/241/214/346/226/271/346/241/210.md +2 -0
  15. package/_packed_docs/design/E2EE_V2/347/256/200/345/214/226/344/270/2721DH/345/212/240Per-AID_Wrap/346/226/271/346/241/210.md +2 -0
  16. package/_packed_docs/design//350/267/250/350/257/255/350/250/200/345/256/271/345/231/250E2E/346/265/213/350/257/225/346/226/271/346/241/210.md +2 -0
  17. package/_packed_docs/protocol/00-/346/200/273/350/247/210/344/270/216/345/210/206/345/261/202.md +2 -0
  18. package/_packed_docs/protocol/00A-/350/256/276/350/256/241/345/216/237/345/210/231-/344/270/272Agent/350/200/214/347/224/237.md +2 -0
  19. package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +2 -0
  20. package/_packed_docs/protocol/02-/350/257/201/344/271/246/344/270/216/344/277/241/344/273/273/344/275/223/347/263/273.md +2 -0
  21. package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +2 -0
  22. package/_packed_docs/protocol/04-Peer-/345/255/220/345/215/217/350/256/256.md +2 -0
  23. package/_packed_docs/protocol/05-Relay-/345/255/220/345/215/217/350/256/256.md +2 -0
  24. package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +2 -0
  25. package/_packed_docs/protocol/08-AUN-E2EE-Group.md +2 -0
  26. package/_packed_docs/protocol/08-AUN-E2EE.md +2 -0
  27. package/_packed_docs/protocol/09-/345/256/211/345/205/250/350/200/203/350/231/221.md +2 -0
  28. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +28 -85
  29. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +49 -0
  30. package/_packed_docs/protocol/12-Stream-/345/255/220/345/215/217/350/256/256.md +2 -0
  31. package/_packed_docs/protocol/13-Agent/350/241/214/344/270/272/350/247/204/350/214/203.md +2 -0
  32. package/_packed_docs/protocol/14-/344/272/244/344/272/222/346/234/272/345/210/266-/345/223/215/345/272/224/346/250/241/345/274/217/344/270/216/350/207/252/344/270/273/346/250/241/345/274/217.md +2 -0
  33. package/_packed_docs/protocol/15-/347/246/273/347/272/277/346/216/250/351/200/201/351/200/232/347/237/245/345/215/217/350/256/256.md +2 -0
  34. package/_packed_docs/protocol/README.md +2 -0
  35. package/_packed_docs/protocol/agent.md/SCHEMA.md +2 -0
  36. package/_packed_docs/protocol/agent.md/examples/codeagent-claudecode.md +2 -0
  37. package/_packed_docs/protocol/agent.md/examples/human-developer.md +2 -0
  38. package/_packed_docs/protocol/agent.md/examples/openclaw-lobster.md +2 -0
  39. package/_packed_docs/protocol/aun-docs-guide.md +2 -0
  40. package/_packed_docs/protocol/index.md +3 -1
  41. package/_packed_docs/protocol//350/215/211/346/241/210-agent.md/347/255/276/345/220/215/345/215/217/350/256/256.md +2 -0
  42. package/_packed_docs/protocol//350/215/211/346/241/210-/346/213/222/347/273/235/344/277/241/345/217/267/345/215/217/350/256/256.md +2 -0
  43. package/_packed_docs/protocol//351/231/204/345/275/225A-/346/234/257/350/257/255/350/241/250.md +2 -0
  44. package/_packed_docs/protocol//351/231/204/345/275/225B-/346/211/251/345/261/225/346/200/247/346/214/207/345/215/227.md +2 -0
  45. package/_packed_docs/protocol//351/231/204/345/275/225C-/347/247/201/351/222/245/347/256/241/347/220/206/344/270/216/350/272/253/344/273/275/346/201/242/345/244/215.md +2 -0
  46. package/_packed_docs/protocol//351/231/204/345/275/225D-Root_CA_/346/262/273/347/220/206/346/234/272/345/210/266.md +2 -0
  47. package/_packed_docs/protocol//351/231/204/345/275/225E-Root_CA_/345/207/206/345/205/245/346/265/201/347/250/213.md +2 -0
  48. package/_packed_docs/protocol//351/231/204/345/275/225F-Issuer_CA_/347/224/263/350/257/267/346/265/201/347/250/213.md +2 -0
  49. package/_packed_docs/protocol//351/231/204/345/275/225G-AID_/345/255/244/345/204/277/351/242/204/351/230/262/344/270/216/346/225/221/346/217/264/346/234/272/345/210/266.md +2 -0
  50. package/_packed_docs/protocol//351/231/204/345/275/225H-Identity/346/234/215/345/212/241/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  51. package/_packed_docs/protocol//351/231/204/345/275/225I-/350/267/250/345/237/237/346/266/210/346/201/257/350/267/257/347/224/261/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  52. package/_packed_docs/protocol//351/231/204/345/275/225J-/345/256/242/346/210/267/347/253/257/346/216/245/345/205/245/347/244/272/344/276/213.md +2 -0
  53. package/_packed_docs/protocol//351/231/204/345/275/225K-Agent_Web/345/217/221/347/216/260/345/215/217/350/256/256.md +2 -0
  54. package/_packed_docs/protocol//351/231/204/345/275/225L-E2EE/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  55. package/_packed_docs/protocol//351/231/204/345/275/225M-JWT/350/256/244/350/257/201/345/256/236/347/216/260/346/214/207/345/215/227.md +2 -0
  56. package/_packed_docs/protocol//351/231/204/345/275/225N-/345/210/206/345/270/203/345/274/217Trace/345/215/217/350/256/256.md +2 -0
  57. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +2 -0
  58. package/_packed_docs/sdk/02-WebSocket/345/215/217/350/256/256.md +2 -0
  59. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +2 -0
  60. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +2 -0
  61. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +2 -0
  62. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +283 -267
  63. package/_packed_docs/sdk/07-/351/224/231/350/257/257/345/244/204/347/220/206.md +4 -1
  64. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +2 -0
  65. package/_packed_docs/sdk/09-collab-rpc-manual.md +550 -0
  66. package/_packed_docs/sdk/09-custody-api-manual.md +2 -0
  67. package/_packed_docs/sdk/09-group-rpc-manual.md +197 -445
  68. package/_packed_docs/sdk/09-message-rpc-manual.md +8 -7
  69. package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -0
  70. package/_packed_docs/sdk/09-payload-reference.md +2 -0
  71. package/_packed_docs/sdk/09-proxy-rpc-manual.md +2 -0
  72. package/_packed_docs/sdk/09-storage-rpc-manual.md +952 -279
  73. package/_packed_docs/sdk/09-stream-rpc-manual.md +2 -0
  74. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +33 -20
  75. package/_packed_docs/sdk/E2EE_V2/346/266/210/346/201/257/351/200/232/344/277/241/346/227/266/345/272/217/345/233/276.md +2 -0
  76. package/_packed_docs/sdk/INDEX.md +46 -29
  77. package/_packed_docs/sdk/Notify/351/200/232/347/237/245/346/226/271/346/241/210.md +2 -0
  78. package/_packed_docs/sdk/README.md +17 -15
  79. package/dist/aid-store.d.ts +25 -0
  80. package/dist/aid-store.js +80 -0
  81. package/dist/aid-store.js.map +1 -1
  82. package/dist/auth.d.ts +2 -0
  83. package/dist/auth.js +99 -8
  84. package/dist/auth.js.map +1 -1
  85. package/dist/client/delivery.d.ts +5 -0
  86. package/dist/client/delivery.js +169 -8
  87. package/dist/client/delivery.js.map +1 -1
  88. package/dist/client/rpc-pipeline.js +58 -26
  89. package/dist/client/rpc-pipeline.js.map +1 -1
  90. package/dist/client/v2-e2ee.js +67 -8
  91. package/dist/client/v2-e2ee.js.map +1 -1
  92. package/dist/client.d.ts +29 -0
  93. package/dist/client.js +301 -20
  94. package/dist/client.js.map +1 -1
  95. package/dist/collab/client.d.ts +38 -0
  96. package/dist/collab/client.js +124 -0
  97. package/dist/collab/client.js.map +1 -0
  98. package/dist/collab/errors.d.ts +15 -0
  99. package/dist/collab/errors.js +60 -0
  100. package/dist/collab/errors.js.map +1 -0
  101. package/dist/collab/index.d.ts +3 -0
  102. package/dist/collab/index.js +4 -0
  103. package/dist/collab/index.js.map +1 -0
  104. package/dist/collab/types.d.ts +110 -0
  105. package/dist/collab/types.js +2 -0
  106. package/dist/collab/types.js.map +1 -0
  107. package/dist/crypto.d.ts +2 -0
  108. package/dist/crypto.js +6 -0
  109. package/dist/crypto.js.map +1 -1
  110. package/dist/errors.d.ts +8 -0
  111. package/dist/errors.js +30 -1
  112. package/dist/errors.js.map +1 -1
  113. package/dist/facades.d.ts +89 -0
  114. package/dist/facades.js +133 -0
  115. package/dist/facades.js.map +1 -0
  116. package/dist/group-fs.d.ts +105 -0
  117. package/dist/group-fs.js +467 -0
  118. package/dist/group-fs.js.map +1 -0
  119. package/dist/group-resources.d.ts +31 -0
  120. package/dist/group-resources.js +84 -0
  121. package/dist/group-resources.js.map +1 -0
  122. package/dist/index.d.ts +6 -2
  123. package/dist/index.js +8 -1
  124. package/dist/index.js.map +1 -1
  125. package/dist/register-flow.d.ts +1 -0
  126. package/dist/register-flow.js +3 -0
  127. package/dist/register-flow.js.map +1 -1
  128. package/dist/service-proxy.d.ts +1 -0
  129. package/dist/service-proxy.js +17 -4
  130. package/dist/service-proxy.js.map +1 -1
  131. package/dist/storage/errors.d.ts +27 -0
  132. package/dist/storage/errors.js +65 -0
  133. package/dist/storage/errors.js.map +1 -0
  134. package/dist/storage/index.d.ts +1 -0
  135. package/dist/storage/index.js +2 -0
  136. package/dist/storage/index.js.map +1 -0
  137. package/dist/storage/lowlevel.d.ts +313 -0
  138. package/dist/storage/lowlevel.js +464 -0
  139. package/dist/storage/lowlevel.js.map +1 -0
  140. package/dist/storage/types.d.ts +58 -0
  141. package/dist/storage/types.js +116 -0
  142. package/dist/storage/types.js.map +1 -0
  143. package/dist/storage/vfs.d.ts +147 -0
  144. package/dist/storage/vfs.js +489 -0
  145. package/dist/storage/vfs.js.map +1 -0
  146. package/dist/tools/cross-sdk-agent.js +421 -1
  147. package/dist/tools/cross-sdk-agent.js.map +1 -1
  148. package/dist/transport.d.ts +3 -0
  149. package/dist/transport.js +76 -22
  150. package/dist/transport.js.map +1 -1
  151. package/dist/version.d.ts +1 -1
  152. package/dist/version.js +1 -1
  153. package/dist/version.js.map +1 -1
  154. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -16,6 +16,7 @@ import * as https from 'node:https';
16
16
  import { URL } from 'node:url';
17
17
  import { configFromMap, getDeviceId, normalizeSlotId } from './config.js';
18
18
  import { CryptoProvider } from './crypto.js';
19
+ import { AIDStore } from './aid-store.js';
19
20
  import { GatewayDiscovery } from './discovery.js';
20
21
  import { DnsResilientNet } from './net.js';
21
22
  import { AUNError, AuthError, ConnectionError, E2EEError, NotFoundError, PermissionError, StateError, TimeoutError, ValidationError, } from './errors.js';
@@ -33,6 +34,9 @@ import { IdentityRuntimeManager } from './client/identity.js';
33
34
  import { LifecycleController } from './client/lifecycle.js';
34
35
  import { PeerDirectory } from './client/peers.js';
35
36
  import { RpcPipeline } from './client/rpc-pipeline.js';
37
+ import { CollabClient } from './collab/client.js';
38
+ import { GroupFacade, MessageFacade, StreamFacade } from './facades.js';
39
+ import { StorageVFS } from './storage/vfs.js';
36
40
  import { V2E2EECoordinator } from './client/v2-e2ee.js';
37
41
  import { GroupStateCoordinator } from './client/group-state.js';
38
42
  import { decryptMessage, } from './v2/e2ee/index.js';
@@ -142,18 +146,25 @@ const NON_IDEMPOTENT_METHODS = new Set([
142
146
  'storage.create_folder', 'storage.rename_folder', 'storage.move_folder',
143
147
  'storage.delete_folder', 'storage.move_object', 'storage.copy_object',
144
148
  'storage.batch_delete', 'storage.set_object_meta', 'storage.append_object',
149
+ 'storage.set_acl', 'storage.remove_acl', 'storage.set_visibility',
150
+ 'storage.issue_token', 'storage.revoke_token',
151
+ 'storage.create_symlink', 'storage.atomic_repoint',
152
+ 'storage.rename_symlink', 'storage.delete_symlink',
153
+ 'storage.fs.mkdir', 'storage.fs.remove', 'storage.fs.rename', 'storage.fs.copy',
154
+ 'storage.fs.mount', 'storage.fs.approve', 'storage.fs.reject', 'storage.fs.unmount',
155
+ 'storage.fs.invalidate_membership',
156
+ 'storage.volume.create', 'storage.volume.renew', 'storage.volume.expire_due',
157
+ 'group.fs.mkdir', 'group.fs.rm', 'group.fs.cp', 'group.fs.mv',
158
+ 'group.fs.mount', 'group.fs.umount',
159
+ 'group.fs.check_upload', 'group.fs.create_upload_session',
160
+ 'group.fs.complete_upload', 'group.fs.create_download_ticket',
145
161
  'auth.create_aid', 'auth.renew_cert', 'auth.rekey',
146
162
  'message.thought.put', 'group.thought.put',
147
- 'group.add_member',
148
- 'group.resources.put', 'group.resources.create_folder',
149
- 'group.resources.rename', 'group.resources.move',
150
- 'group.resources.mount_object', 'group.resources.update',
151
- 'group.resources.delete', 'group.resources.cleanup_by_storage_ref',
152
- 'group.resources.request_add', 'group.resources.request_mount_object',
153
- 'group.resources.direct_add', 'group.resources.approve_request',
154
- 'group.resources.reject_request', 'group.resources.unmount',
155
- 'group.resources.get_access',
156
- 'group.resources.resolve_access_ticket',
163
+ 'group.add_member', 'group.bind_group_aid', 'group.complete_transfer',
164
+ 'collab.create', 'collab.commit', 'collab.clone',
165
+ 'collab.prune', 'collab.unregister',
166
+ 'collab.tag.create', 'collab.tag.restore',
167
+ 'collab.tag.rm', 'collab.tag.prune',
157
168
  ]);
158
169
  /** 需要客户端签名的关键方法。运行时逻辑已迁入 RpcPipeline,此处保留给源码审计测试。 */
159
170
  const SIGNED_METHODS = new Set([
@@ -170,26 +181,36 @@ const SIGNED_METHODS = new Set([
170
181
  'group.leave', 'group.remove_member', 'group.update_rules',
171
182
  'group.update', 'group.update_announcement',
172
183
  'group.update_join_requirements', 'group.set_role',
173
- 'group.transfer_owner', 'group.review_join_request',
184
+ 'group.transfer_owner', 'group.bind_group_aid', 'group.complete_transfer',
185
+ 'group.review_join_request',
174
186
  'group.batch_review_join_request',
175
187
  'group.request_join', 'group.use_invite_code',
176
188
  'group.thought.put',
177
189
  'message.thought.put',
178
190
  'group.set_settings',
179
- 'group.resources.put', 'group.resources.create_folder',
180
- 'group.resources.rename', 'group.resources.move',
181
- 'group.resources.mount_object', 'group.resources.update',
182
- 'group.resources.delete', 'group.resources.cleanup_by_storage_ref',
183
- 'group.resources.request_add', 'group.resources.request_mount_object',
184
- 'group.resources.direct_add', 'group.resources.approve_request',
185
- 'group.resources.reject_request', 'group.resources.unmount',
186
- 'group.resources.get_access', 'group.resources.resolve_access_ticket',
187
191
  'storage.put_object', 'storage.delete_object', 'storage.get_by_share',
188
192
  'storage.create_share_link', 'storage.revoke_share_link',
189
193
  'storage.create_upload_session', 'storage.complete_upload',
190
194
  'storage.create_folder', 'storage.rename_folder', 'storage.move_folder',
191
195
  'storage.delete_folder', 'storage.move_object', 'storage.copy_object',
192
196
  'storage.batch_delete', 'storage.set_object_meta', 'storage.append_object',
197
+ 'storage.set_acl', 'storage.remove_acl', 'storage.set_visibility',
198
+ 'storage.check_access',
199
+ 'storage.issue_token', 'storage.revoke_token',
200
+ 'storage.create_symlink', 'storage.atomic_repoint',
201
+ 'storage.rename_symlink', 'storage.delete_symlink',
202
+ 'storage.fs.mkdir', 'storage.fs.remove', 'storage.fs.rename', 'storage.fs.copy',
203
+ 'storage.fs.mount', 'storage.fs.approve', 'storage.fs.reject', 'storage.fs.unmount',
204
+ 'storage.fs.invalidate_membership',
205
+ 'storage.volume.create', 'storage.volume.renew', 'storage.volume.expire_due',
206
+ 'group.fs.mkdir', 'group.fs.rm', 'group.fs.cp', 'group.fs.mv',
207
+ 'group.fs.mount', 'group.fs.umount',
208
+ 'group.fs.check_upload', 'group.fs.create_upload_session',
209
+ 'group.fs.complete_upload', 'group.fs.create_download_ticket',
210
+ 'collab.create', 'collab.commit', 'collab.clone',
211
+ 'collab.prune', 'collab.unregister',
212
+ 'collab.tag.create', 'collab.tag.restore',
213
+ 'collab.tag.rm', 'collab.tag.prune',
193
214
  'group.commit_state',
194
215
  'group.ban', 'group.unban',
195
216
  'group.dissolve', 'group.suspend', 'group.resume',
@@ -226,6 +247,22 @@ function _v2BytesEqual(a, b) {
226
247
  function formatCaughtError(error) {
227
248
  return error instanceof Error ? error : String(error);
228
249
  }
250
+ const RELOGIN_REFRESH_ERRORS = new Set([
251
+ 'missing refresh_token',
252
+ 'invalid_or_expired_refresh_token',
253
+ 'refresh not supported',
254
+ ]);
255
+ function authErrorRequiresRelogin(error) {
256
+ const data = error.data;
257
+ if (isJsonObject(data)) {
258
+ if (data.relogin_required === true)
259
+ return true;
260
+ const code = String(data.error ?? '').trim().toLowerCase();
261
+ if (RELOGIN_REFRESH_ERRORS.has(code))
262
+ return true;
263
+ }
264
+ return RELOGIN_REFRESH_ERRORS.has(error.message.trim().toLowerCase());
265
+ }
229
266
  function normalizeDeliveryModeConfig(raw, opts = {}) {
230
267
  const defaultMode = String(opts.defaultMode ?? 'fanout').trim().toLowerCase() || 'fanout';
231
268
  const defaultRouting = String(opts.defaultRouting ?? 'round_robin').trim().toLowerCase() || 'round_robin';
@@ -497,6 +534,11 @@ export class AUNClient {
497
534
  _delivery;
498
535
  _v2E2EE;
499
536
  _groupState;
537
+ _storage;
538
+ _collab;
539
+ _message;
540
+ _group;
541
+ _stream;
500
542
  constructor(aid) {
501
543
  if (aid !== null && aid !== undefined && !isAIDObject(aid)) {
502
544
  throw new ValidationError('AUNClient only accepts an AID object or no argument');
@@ -635,6 +677,36 @@ export class AUNClient {
635
677
  get aid() {
636
678
  return this._aid;
637
679
  }
680
+ /** AUN Storage VFS 入口 */
681
+ get storage() {
682
+ if (!this._storage)
683
+ this._storage = new StorageVFS(this);
684
+ return this._storage;
685
+ }
686
+ /** AUN Collab 入口 */
687
+ get collab() {
688
+ if (!this._collab)
689
+ this._collab = new CollabClient(this);
690
+ return this._collab;
691
+ }
692
+ /** Message facade 入口 */
693
+ get message() {
694
+ if (!this._message)
695
+ this._message = new MessageFacade(this);
696
+ return this._message;
697
+ }
698
+ /** Group facade 入口 */
699
+ get group() {
700
+ if (!this._group)
701
+ this._group = new GroupFacade(this);
702
+ return this._group;
703
+ }
704
+ /** Stream facade 入口 */
705
+ get stream() {
706
+ if (!this._stream)
707
+ this._stream = new StreamFacade(this);
708
+ return this._stream;
709
+ }
638
710
  /** 当前 AID 值对象 */
639
711
  get currentAid() {
640
712
  return this._currentAid;
@@ -882,6 +954,201 @@ export class AUNClient {
882
954
  async call(method, params) {
883
955
  return await this._rpcPipeline.call(method, params);
884
956
  }
957
+ async createGroup(params = {}) {
958
+ if (!isJsonObject(params)) {
959
+ throw new ValidationError('createGroup params must be an object');
960
+ }
961
+ const payload = { ...params };
962
+ const groupName = String(payload.group_name ?? payload.groupName ?? '').trim();
963
+ if (!groupName) {
964
+ return await this.call('group.create', payload);
965
+ }
966
+ const keyPair = new CryptoProvider().generateIdentity();
967
+ payload.public_key = keyPair.public_key_der_b64;
968
+ payload.curve = keyPair.curve;
969
+ const result = await this.call('group.create', payload);
970
+ const resultMap = isJsonObject(result) ? result : {};
971
+ const group = isJsonObject(resultMap.group) ? resultMap.group : {};
972
+ const aidCert = isJsonObject(resultMap.aid_cert) ? resultMap.aid_cert : {};
973
+ const groupAid = String(group.group_aid ?? resultMap.group_aid ?? '').trim();
974
+ const certPem = String(aidCert.cert ?? aidCert.cert_pem ?? resultMap.cert ?? resultMap.cert_pem ?? '').trim();
975
+ if (!groupAid || !certPem) {
976
+ throw new ValidationError('group.create named group response missing group.group_aid or aid_cert.cert');
977
+ }
978
+ const store = new AIDStore({
979
+ aunPath: this._configModel.aunPath,
980
+ encryptionSeed: this._configModel.seedPassword ?? '',
981
+ slotId: this._slotId,
982
+ verifySsl: this._configModel.verifySsl,
983
+ rootCaPath: this._configModel.rootCaPath,
984
+ debug: this._configModel.debug,
985
+ });
986
+ try {
987
+ const imported = store.importGroupIdentity(groupAid, {
988
+ private_key_pem: keyPair.private_key_pem,
989
+ public_key_der_b64: keyPair.public_key_der_b64,
990
+ curve: keyPair.curve,
991
+ cert_pem: certPem,
992
+ });
993
+ if (!imported.ok) {
994
+ throw new ValidationError(imported.error.message);
995
+ }
996
+ }
997
+ finally {
998
+ store.close();
999
+ }
1000
+ return result;
1001
+ }
1002
+ async bindGroupAid(params = {}, options = {}) {
1003
+ if (!isJsonObject(params)) {
1004
+ throw new ValidationError('bindGroupAid params must be an object');
1005
+ }
1006
+ const store = options.aidStore;
1007
+ if (!store) {
1008
+ throw new ValidationError('bindGroupAid requires aidStore');
1009
+ }
1010
+ const keyPair = new CryptoProvider().generateIdentity();
1011
+ const payload = { ...params };
1012
+ payload.public_key = keyPair.public_key_der_b64;
1013
+ payload.curve = keyPair.curve;
1014
+ const result = await this.call('group.bind_group_aid', payload);
1015
+ const resultMap = isJsonObject(result) ? result : {};
1016
+ const group = isJsonObject(resultMap.group) ? resultMap.group : {};
1017
+ const aidCert = isJsonObject(resultMap.aid_cert) ? resultMap.aid_cert : {};
1018
+ const groupAid = String(group.group_aid ?? resultMap.group_aid ?? '').trim();
1019
+ const certPem = String(aidCert.cert ?? aidCert.cert_pem ?? resultMap.cert ?? resultMap.cert_pem ?? '').trim();
1020
+ if (!groupAid || !certPem) {
1021
+ throw new ValidationError('group.bind_group_aid response missing group.group_aid or aid_cert.cert');
1022
+ }
1023
+ const imported = store.importGroupIdentity(groupAid, {
1024
+ private_key_pem: keyPair.private_key_pem,
1025
+ public_key_der_b64: keyPair.public_key_der_b64,
1026
+ curve: keyPair.curve,
1027
+ cert_pem: certPem,
1028
+ });
1029
+ if (!imported.ok) {
1030
+ throw new ValidationError(imported.error.message);
1031
+ }
1032
+ return result;
1033
+ }
1034
+ async startGroupTransfer(params = {}, options = {}) {
1035
+ if (!isJsonObject(params)) {
1036
+ throw new ValidationError('startGroupTransfer params must be an object');
1037
+ }
1038
+ const store = options.aidStore;
1039
+ if (!store) {
1040
+ throw new ValidationError('startGroupTransfer requires aidStore');
1041
+ }
1042
+ const groupId = String(params.group_id ?? '').trim();
1043
+ const newOwner = String(params.new_owner ?? '').trim();
1044
+ if (!groupId || !newOwner) {
1045
+ throw new ValidationError('startGroupTransfer requires group_id and new_owner');
1046
+ }
1047
+ let groupAid = String(params.group_aid ?? '').trim();
1048
+ if (!groupAid) {
1049
+ const info = await this.call('group.get', { group_id: groupId });
1050
+ const infoMap = isJsonObject(info) ? info : {};
1051
+ const grp = isJsonObject(infoMap.group) ? infoMap.group : infoMap;
1052
+ groupAid = String(grp.group_aid ?? '').trim();
1053
+ }
1054
+ if (!groupAid) {
1055
+ throw new ValidationError('startGroupTransfer: unable to determine group_aid');
1056
+ }
1057
+ const loaded = store.load(groupAid);
1058
+ if (!loaded.ok || !loaded.data) {
1059
+ throw new ValidationError(`startGroupTransfer: group_aid identity not found: ${groupAid}`);
1060
+ }
1061
+ const aidObj = loaded.data.aid;
1062
+ if (!aidObj.isPrivateKeyValid() || !aidObj.privateKeyPem) {
1063
+ throw new ValidationError(`startGroupTransfer: group_aid private key not found: ${groupAid}`);
1064
+ }
1065
+ const nonce = crypto.randomUUID().replace(/-/g, '');
1066
+ const issuedMs = Date.now();
1067
+ const canonical = [
1068
+ 'aun-group-owner-transfer-v1',
1069
+ groupId.toLowerCase(),
1070
+ groupAid.toLowerCase(),
1071
+ newOwner.toLowerCase(),
1072
+ nonce,
1073
+ String(issuedMs),
1074
+ ].join('|');
1075
+ const signed = aidObj.sign(canonical);
1076
+ if (!signed.ok) {
1077
+ throw new ValidationError(`startGroupTransfer: sign failed: ${signed.error.message}`);
1078
+ }
1079
+ const payload = { ...params, group_aid: groupAid };
1080
+ payload.transfer_auth = { nonce, issued_ms: issuedMs, signature: signed.data.signature };
1081
+ return await this.call('group.transfer_owner', payload);
1082
+ }
1083
+ async completeGroupTransfer(params = {}, options = {}) {
1084
+ if (!isJsonObject(params)) {
1085
+ throw new ValidationError('completeGroupTransfer params must be an object');
1086
+ }
1087
+ const store = options.aidStore;
1088
+ if (!store) {
1089
+ throw new ValidationError('completeGroupTransfer requires aidStore');
1090
+ }
1091
+ const keyPair = new CryptoProvider().generateIdentity();
1092
+ const payload = { ...params };
1093
+ const groupId = String(params.group_id ?? '').trim();
1094
+ if (!groupId) {
1095
+ throw new ValidationError('completeGroupTransfer requires group_id');
1096
+ }
1097
+ let groupAid = String(params.group_aid ?? '').trim();
1098
+ if (!groupAid) {
1099
+ const info = await this.call('group.get', { group_id: groupId });
1100
+ const infoMap = isJsonObject(info) ? info : {};
1101
+ const grp = isJsonObject(infoMap.group) ? infoMap.group : infoMap;
1102
+ groupAid = String(grp.group_aid ?? '').trim();
1103
+ }
1104
+ if (!groupAid) {
1105
+ throw new ValidationError('completeGroupTransfer: unable to determine group_aid');
1106
+ }
1107
+ const current = this.currentAid;
1108
+ const newOwner = String(current?.aid ?? '').trim();
1109
+ if (!current || !newOwner || !current.isPrivateKeyValid()) {
1110
+ throw new ValidationError('completeGroupTransfer requires current new-owner AID with private key');
1111
+ }
1112
+ const nonce = crypto.randomUUID().replace(/-/g, '');
1113
+ const issuedMs = Date.now();
1114
+ const publicKeyHash = crypto.createHash('sha256').update(keyPair.public_key_der_b64, 'utf8').digest('hex');
1115
+ const canonical = [
1116
+ 'aun-group-owner-transfer-accept-v1',
1117
+ groupId.toLowerCase(),
1118
+ groupAid.toLowerCase(),
1119
+ newOwner.toLowerCase(),
1120
+ publicKeyHash,
1121
+ nonce,
1122
+ String(issuedMs),
1123
+ ].join('|');
1124
+ const signed = current.sign(canonical);
1125
+ if (!signed.ok) {
1126
+ throw new ValidationError(`completeGroupTransfer: accept sign failed: ${signed.error.message}`);
1127
+ }
1128
+ payload.group_aid = groupAid;
1129
+ payload.public_key = keyPair.public_key_der_b64;
1130
+ payload.curve = keyPair.curve;
1131
+ payload.transfer_accept = { nonce, issued_ms: issuedMs, signature: signed.data.signature };
1132
+ const result = await this.call('group.complete_transfer', payload);
1133
+ const resultMap = isJsonObject(result) ? result : {};
1134
+ const group = isJsonObject(resultMap.group) ? resultMap.group : {};
1135
+ const aidCert = isJsonObject(resultMap.aid_cert) ? resultMap.aid_cert : {};
1136
+ const returnedGroupAid = String(group.group_aid ?? resultMap.group_aid ?? '').trim();
1137
+ const certPem = String(aidCert.cert ?? aidCert.cert_pem ?? resultMap.cert ?? resultMap.cert_pem ?? '').trim();
1138
+ if (!returnedGroupAid || !certPem) {
1139
+ throw new ValidationError('group.complete_transfer response missing group.group_aid or aid_cert.cert');
1140
+ }
1141
+ const imported = store.importGroupIdentity(returnedGroupAid, {
1142
+ private_key_pem: keyPair.private_key_pem,
1143
+ public_key_der_b64: keyPair.public_key_der_b64,
1144
+ curve: keyPair.curve,
1145
+ cert_pem: certPem,
1146
+ });
1147
+ if (!imported.ok) {
1148
+ throw new ValidationError(imported.error.message);
1149
+ }
1150
+ return result;
1151
+ }
885
1152
  static _notifyParamsSizeOk(params) {
886
1153
  return new TextEncoder().encode(JSON.stringify(params)).length <= MAX_NOTIFY_PAYLOAD_SIZE;
887
1154
  }
@@ -2624,6 +2891,18 @@ export class AUNClient {
2624
2891
  }
2625
2892
  catch (exc) {
2626
2893
  if (exc instanceof AuthError) {
2894
+ if (authErrorRequiresRelogin(exc)) {
2895
+ this._clientLog.warn(`token refresh requires relogin, stopping refresh loop and triggering reconnect: ${exc.message}`);
2896
+ await this._dispatcher.publish('token.refresh_exhausted', {
2897
+ aid: this._identity?.aid ?? null,
2898
+ consecutive_failures: 1,
2899
+ last_error: String(exc),
2900
+ relogin_required: true,
2901
+ });
2902
+ this._tokenRefreshFailures = 0;
2903
+ await this._handleTransportDisconnect(new Error('token refresh relogin required, triggering reconnect'));
2904
+ return;
2905
+ }
2627
2906
  this._tokenRefreshFailures++;
2628
2907
  if (this._tokenRefreshFailures >= 3) {
2629
2908
  this._clientLog.warn(`token refresh failed ${this._tokenRefreshFailures} consecutive times, stopping refresh loop and triggering reconnect`);
@@ -2633,7 +2912,7 @@ export class AUNClient {
2633
2912
  last_error: String(exc),
2634
2913
  });
2635
2914
  this._tokenRefreshFailures = 0;
2636
- this._handleTransportDisconnect(new Error('token refresh exhausted, triggering reconnect'));
2915
+ await this._handleTransportDisconnect(new Error('token refresh exhausted, triggering reconnect'));
2637
2916
  return;
2638
2917
  }
2639
2918
  this._clientLog.debug(`token refresh failed (${this._tokenRefreshFailures}/3), will retry: ${exc}`);
@@ -2750,10 +3029,12 @@ export class AUNClient {
2750
3029
  eventPayload.code = disconnectInfo.code;
2751
3030
  }
2752
3031
  await this._dispatcher.publish('state_change', eventPayload);
3032
+ this._reconnectActive = false;
2753
3033
  return;
2754
3034
  }
2755
3035
  // 1000 = 正常关闭, 1006 = 网络异常断开(无 close frame),其他 code = 服务端主动关闭
2756
3036
  const serverInitiated = closeCode !== undefined && closeCode !== 1000 && closeCode !== 1006;
3037
+ this._reconnectActive = false;
2757
3038
  this._startReconnect(serverInitiated);
2758
3039
  }
2759
3040
  /** 启动重连循环(默认无限重试 + 指数退避 + 固定上限抖动,仅在不可重试错误、close() 或 max_attempts 耗尽时终止) */