@agentunion/fastaun-browser 0.4.0 → 0.4.1

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.
@@ -1,4 +1,4 @@
1
- # AUN SDK 重构设计方案 v4.0
1
+ # AUN SDK 重构设计方案 v4.2
2
2
 
3
3
  ## 一、设计原则
4
4
 
@@ -40,6 +40,9 @@ class AIDStore {
40
40
  encryptionSeed: string; // 必传:加密种子(可为空字符串 '')
41
41
  deviceId?: string; // 默认 getDeviceId(),同一 AID 最多 10 个设备在线
42
42
  slotId?: string; // 默认 'default',同设备最多 10 个 slot 在线
43
+ verifySsl?: boolean; // 默认 true,测试环境可设为 false
44
+ rootCaPath?: string; // 自定义根证书路径,私有部署使用
45
+ debug?: boolean; // 开启调试日志,默认 false
43
46
  });
44
47
  }
45
48
  ```
@@ -49,6 +52,9 @@ class AIDStore {
49
52
  - `encryptionSeed` 可以是空字符串 `''`,表示不加密
50
53
  - 应用层统一管理加密种子,SDK 不持久化
51
54
  - `deviceId` + `slotId` 构成消费通道,影响 V2 session 密钥存储和消息序号命名空间
55
+ - `verifySsl: false` 仅用于测试环境,生产环境不应关闭
56
+ - `rootCaPath` 用于私有部署时指定自定义根证书
57
+ - `debug: true` 开启详细调试日志输出
52
58
  - 同一进程内可创建多个 AIDStore 实例(指向不同 keystore 或不同 slot)
53
59
 
54
60
  **示例**:
@@ -72,10 +78,12 @@ const store = new AIDStore({
72
78
 
73
79
  ### 2.2 AIDStore 加载与注册
74
80
 
75
- #### `load(aid: string): Promise<Result<{ aid: AID }>>`
81
+ #### `load(aid: string): Result<{ aid: AID }>`
76
82
 
77
83
  从本地 keystore 加载 AID(证书 + 私钥若有)。
78
84
 
85
+ > **注意**:JS SDK 因底层使用 IndexedDB(浏览器异步 API),保持 `Promise<Result<{ aid: AID }>>` 为平台例外。
86
+
79
87
  **流程**:
80
88
  1. 从 `{aunPath}/AIDs/{aid}/public/certs/` 读证书
81
89
  2. 链验证 + 有效期检查
@@ -92,7 +100,7 @@ const store = new AIDStore({
92
100
  **示例**:
93
101
  ```typescript
94
102
  const store = new AIDStore({ aunPath: '...', encryptionSeed: '...' });
95
- const result = await store.load('alice.aid.pub');
103
+ const result = store.load('alice.aid.pub');
96
104
 
97
105
  if (result.ok) {
98
106
  const me = result.data.aid;
@@ -131,7 +139,7 @@ const result = await store.register('alice.aid.pub');
131
139
 
132
140
  if (result.ok) {
133
141
  // 注册成功,加载身份
134
- const loadResult = await store.load('alice.aid.pub');
142
+ const loadResult = store.load('alice.aid.pub');
135
143
  const me = loadResult.data!.aid;
136
144
  } else {
137
145
  console.log('注册失败:', result.error.code);
@@ -140,7 +148,7 @@ if (result.ok) {
140
148
 
141
149
  ---
142
150
 
143
- #### `list(): Promise<Result<{ identities: AIDInfo[] }>>`
151
+ #### `list(): Result<{ identities: AIDInfo[] }>`
144
152
 
145
153
  列出本地所有有私钥的 AID 元信息。
146
154
 
@@ -155,6 +163,7 @@ type AIDInfo = {
155
163
  aid: string;
156
164
  certNotAfter: Date;
157
165
  certIssuer: string;
166
+ certFingerprint: string;
158
167
  };
159
168
 
160
169
  // 成功
@@ -164,7 +173,7 @@ type AIDInfo = {
164
173
  **示例**:
165
174
  ```typescript
166
175
  const store = new AIDStore({ aunPath: '...', encryptionSeed: '...' });
167
- const result = await store.list();
176
+ const result = store.list();
168
177
 
169
178
  if (result.ok) {
170
179
  console.log('本地身份:', result.data.identities.map(i => i.aid));
@@ -214,7 +223,7 @@ if (result.ok) {
214
223
 
215
224
  ### 2.3 AIDStore 解析对端
216
225
 
217
- #### `resolve(aid: string, opts?: ResolveOpts): Promise<Result<ResolveData>>`
226
+ #### `resolve(aid: string, opts?: ResolveOpts): Promise<Result<ResolveResult>>`
218
227
 
219
228
  **一站式解析对端 AID**:下载证书 → 验签证书 → 缓存到本地 → 下载 agent.md → 验签 agent.md。
220
229
 
@@ -236,23 +245,24 @@ type ResolveOpts = {
236
245
 
237
246
  **返回**:
238
247
  ```typescript
239
- type ResolveData = {
248
+ type ResolveResult = {
240
249
  aid: AID; // PeerOnly AID 对象
241
- agentMd?: {
250
+ agent_md?: {
242
251
  content: string;
243
252
  verification: {
244
- status: 'verified' | 'invalid' | 'unsigned';
253
+ status: string;
245
254
  reason?: string;
246
255
  };
256
+ cert_pem: string;
247
257
  };
248
258
  source: {
249
- certFromCache: boolean; // 证书来自本地缓存
250
- agentMdFetched: boolean; // agent.md 已下载
259
+ cert_from_cache: boolean; // 证书来自本地缓存
260
+ agent_md_fetched: boolean; // agent.md 已下载
251
261
  };
252
262
  };
253
263
 
254
264
  // 成功
255
- { ok: true, data: ResolveData }
265
+ { ok: true, data: ResolveResult }
256
266
  // 失败
257
267
  { ok: false, error: { code, message } }
258
268
  ```
@@ -269,7 +279,7 @@ type ResolveData = {
269
279
 
270
280
  **关键设计原则**:
271
281
  - 网络/资源不存在 → 返回 `error`(应用层无法继续)
272
- - 内容验证失败(签名 invalid / unsigned)→ 仍 `ok: true`,通过 `data.agentMd.verification.status` 标记,让应用层决定
282
+ - 内容验证失败(签名 invalid / unsigned)→ 仍 `ok: true`,通过 `data.agent_md.verification.status` 标记,让应用层决定
273
283
 
274
284
  **示例**:
275
285
  ```typescript
@@ -277,13 +287,13 @@ const store = new AIDStore({ aunPath: '...', encryptionSeed: '' });
277
287
  const result = await store.resolve('bob.aid.pub');
278
288
 
279
289
  if (result.ok) {
280
- const { aid: peer, agentMd, source } = result.data;
281
- console.log('证书来自:', source.certFromCache ? '本地缓存' : '网络下载');
290
+ const { aid: peer, agent_md, source } = result.data;
291
+ console.log('证书来自:', source.cert_from_cache ? '本地缓存' : '网络下载');
282
292
 
283
- if (agentMd?.verification.status === 'verified') {
284
- console.log('名片有效:', agentMd.content);
285
- } else if (agentMd?.verification.status === 'invalid') {
286
- console.log('警告:名片签名无效,原因:', agentMd.verification.reason);
293
+ if (agent_md?.verification.status === 'verified') {
294
+ console.log('名片有效:', agent_md.content);
295
+ } else if (agent_md?.verification.status === 'invalid') {
296
+ console.log('警告:名片签名无效,原因:', agent_md.verification.reason);
287
297
  } else {
288
298
  console.log('名片未签名');
289
299
  }
@@ -303,7 +313,7 @@ if (result.ok) {
303
313
 
304
314
  ---
305
315
 
306
- #### `fetchAgentMd(aid: string): Promise<Result<AgentMdFetchData>>`
316
+ #### `fetchAgentMd(aid: string): Promise<Result<FetchAgentMdResult>>`
307
317
 
308
318
  下载 agent.md + 自动拉证书 + 验签。比 `resolve` 更轻量,适用于"只想拿名片"的场景。
309
319
 
@@ -315,13 +325,16 @@ if (result.ok) {
315
325
 
316
326
  **返回**:
317
327
  ```typescript
318
- type AgentMdFetchData = {
328
+ type FetchAgentMdResult = {
329
+ aid: string;
319
330
  content: string;
320
331
  verification: {
321
- status: 'verified' | 'invalid' | 'unsigned';
332
+ status: string;
322
333
  reason?: string;
323
334
  };
324
- certPem: string;
335
+ cert_pem: string;
336
+ etag: string;
337
+ last_modified: string;
325
338
  };
326
339
  ```
327
340
 
@@ -329,32 +342,37 @@ type AgentMdFetchData = {
329
342
 
330
343
  ---
331
344
 
332
- #### `checkAgentMd(aid: string, ttlDays?: number): Promise<Result<AgentMdCheckData>>`
345
+ #### `checkAgentMd(aid: string, ttlDays?: number): Promise<Result<CheckAgentMdResult>>`
333
346
 
334
347
  比对本地缓存与远端 etag,决定是否需要重新拉取。
335
348
 
336
349
  **返回**:
337
350
  ```typescript
338
- type AgentMdCheckData = {
339
- needsUpdate: boolean;
340
- localEtag?: string;
341
- remoteEtag?: string;
342
- lastModified?: string;
351
+ type CheckAgentMdResult = {
352
+ aid: string;
353
+ local_found: boolean;
354
+ remote_found: boolean;
355
+ local_etag: string;
356
+ remote_etag: string;
357
+ needs_update: boolean;
358
+ ttl_days: number;
343
359
  };
344
360
  ```
345
361
 
346
362
  ---
347
363
 
348
- #### `headAgentMd(aid: string): Promise<Result<AgentMdHeadData>>`
364
+ #### `headAgentMd(aid: string): Promise<Result<HeadAgentMdResult>>`
349
365
 
350
366
  HEAD 请求拿 agent.md 元数据,**判断对端是否发布了名片**。
351
367
 
352
368
  **返回**:
353
369
  ```typescript
354
- type AgentMdHeadData = {
370
+ type HeadAgentMdResult = {
371
+ aid: string;
372
+ found: boolean;
355
373
  etag: string;
356
- lastModified: string;
357
- contentLength: number;
374
+ last_modified: string;
375
+ content_length: number;
358
376
  };
359
377
  ```
360
378
 
@@ -371,14 +389,17 @@ type AgentMdHeadData = {
371
389
  | `changeSeed(oldSeed, newSeed)` | 否 | 更换加密种子:用旧种子解密所有私钥 → 用新种子重新加密 → 落盘 |
372
390
  | `diagnose(aid)` | 是 | 本地状态 + 远端注册状态对比 |
373
391
 
374
- 所有方法返回 `Promise<Result<T>>`:
392
+ `renewCert` / `rekey` / `diagnose` 返回 `Promise<Result<T>>`,`changeSeed` 为同步方法返回 `Result<T>`:
375
393
 
376
394
  ```typescript
395
+ // changeSeed 签名(同步)
396
+ changeSeed(oldSeed: string, newSeed: string): Result<{ changed: true; count: number }>
397
+
377
398
  // renewCert 成功
378
- { ok: true, data: { renewed: true, newCertNotAfter: Date } }
399
+ { ok: true, data: { renewed: true, new_cert_not_after: Date, new_fingerprint: string } }
379
400
 
380
401
  // rekey 成功
381
- { ok: true, data: { rekeyed: true, newFingerprint: string } }
402
+ { ok: true, data: { rekeyed: true, new_cert_not_after: Date, new_fingerprint: string } }
382
403
 
383
404
  // changeSeed 成功
384
405
  { ok: true, data: { changed: true, count: number } } // 重新加密的私钥数量
@@ -387,14 +408,42 @@ type AgentMdHeadData = {
387
408
  {
388
409
  ok: true,
389
410
  data: {
390
- localValid: boolean;
391
- remoteRegistered: boolean;
392
- certMatch: boolean;
411
+ aid: string;
412
+ status: string;
413
+ local_valid: boolean;
414
+ remote_registered: boolean;
393
415
  suggestions: string[];
416
+ local: Record<string, unknown>;
417
+ remote: Record<string, unknown>;
394
418
  }
395
419
  }
396
420
  ```
397
421
 
422
+ **返回类型定义**:
423
+ ```typescript
424
+ type RenewCertResult = {
425
+ renewed: true;
426
+ new_cert_not_after: Date;
427
+ new_fingerprint: string;
428
+ };
429
+
430
+ type RekeyResult = {
431
+ rekeyed: true;
432
+ new_cert_not_after: Date;
433
+ new_fingerprint: string;
434
+ };
435
+
436
+ type DiagnoseResult = {
437
+ aid: string;
438
+ status: string;
439
+ local_valid: boolean;
440
+ remote_registered: boolean;
441
+ suggestions: string[];
442
+ local: Record<string, unknown>;
443
+ remote: Record<string, unknown>;
444
+ };
445
+ ```
446
+
398
447
  **错误码**:
399
448
  - `renewCert`: `CERT_RENEWAL_FAILED` | `PRIVATE_KEY_REQUIRED` | `NETWORK_ERROR`
400
449
  - `rekey`: `REKEY_FAILED` | `PRIVATE_KEY_REQUIRED` | `NETWORK_ERROR`
@@ -408,12 +457,12 @@ const store = new AIDStore({ aunPath, encryptionSeed: 'old-seed' });
408
457
  const renewResult = await store.renewCert('alice.aid.pub');
409
458
  if (renewResult.ok) {
410
459
  // 重新加载拿新证书
411
- const me = (await store.load('alice.aid.pub')).data!.aid;
460
+ const me = store.load('alice.aid.pub').data!.aid;
412
461
  console.log('新证书有效期至:', me.certNotAfter);
413
462
  }
414
463
 
415
- // 换加密种子
416
- const seedResult = await store.changeSeed('old-seed', 'new-seed');
464
+ // 换加密种子(同步)
465
+ const seedResult = store.changeSeed('old-seed', 'new-seed');
417
466
  if (seedResult.ok) {
418
467
  console.log(`已重新加密 ${seedResult.data.count} 个私钥`);
419
468
  }
@@ -431,6 +480,11 @@ AID 是不可变的身份值对象,由 AIDStore 创建,外部不直接 `new
431
480
  |------|------|------|
432
481
  | `aid` | string | AID 标识符(如 `'alice.aid.pub'`) |
433
482
  | `aunPath` | string | keystore 根目录(来自创建它的 store) |
483
+ | `deviceId` | string | 来自创建它的 AIDStore 的 deviceId |
484
+ | `slotId` | string | 来自创建它的 AIDStore 的 slotId |
485
+ | `verifySsl` | boolean | 来自创建它的 AIDStore 的 verifySsl |
486
+ | `rootCaPath` | string \| null | 来自创建它的 AIDStore 的 rootCaPath |
487
+ | `debug` | boolean | 来自创建它的 AIDStore 的 debug |
434
488
  | `certPem` | string | PEM 格式证书 |
435
489
  | `publicKey` | string | DER base64 公钥 |
436
490
  | `certSubject` | string | 证书 subject |
@@ -486,7 +540,7 @@ type VerifyResult = {
486
540
  **示例**:
487
541
  ```typescript
488
542
  // 签名
489
- const me = (await store.load('alice.aid.pub')).data!.aid;
543
+ const me = store.load('alice.aid.pub').data!.aid;
490
544
  const signResult = me.signAgentMd(content);
491
545
  if (signResult.ok) {
492
546
  const signed = signResult.data.signed;
@@ -520,7 +574,7 @@ type Result<T> =
520
574
 
521
575
  **TypeScript 使用模式**:
522
576
  ```typescript
523
- const result = await store.load('alice.aid.pub');
577
+ const result = store.load('alice.aid.pub');
524
578
  if (!result.ok) {
525
579
  // 处理错误
526
580
  console.log(result.error.code, result.error.message);
@@ -537,10 +591,10 @@ const me = result.data.aid;
537
591
  | 场景 | 推荐方法 | 一行代码示例 |
538
592
  |------|---------|--------------|
539
593
  | 检查 AID 名字是否可注册 | `store.exists(aid)` | `(await store.exists('alice.aid.pub')).data?.exists === false` |
540
- | 注册新身份 | `store.register` + `store.load` | `await store.register('alice.aid.pub'); await store.load('alice.aid.pub')` |
541
- | 加载本地身份 | `store.load(aid)` | `(await store.load('alice.aid.pub')).data!.aid` |
542
- | 列出本地所有身份 | `store.list()` | `(await store.list()).data!.identities` |
543
- | **一站式解析对端**(推荐)| `store.resolve(aid)` | `const { aid: peer, agentMd } = (await store.resolve('bob')).data!` |
594
+ | 注册新身份 | `store.register` + `store.load` | `await store.register('alice.aid.pub'); store.load('alice.aid.pub')` |
595
+ | 加载本地身份 | `store.load(aid)` | `store.load('alice.aid.pub').data!.aid` |
596
+ | 列出本地所有身份 | `store.list()` | `store.list().data!.identities` |
597
+ | **一站式解析对端**(推荐)| `store.resolve(aid)` | `const { aid: peer, agent_md } = (await store.resolve('bob')).data!` |
544
598
  | 只想拿对端 agent.md | `store.fetchAgentMd(aid)` | `(await store.fetchAgentMd('bob.aid.pub')).data?.content` |
545
599
  | 离线签名 agent.md | `load` → `signAgentMd` | `me.signAgentMd(content).data?.signed` |
546
600
  | 离线验签 agent.md | `load`/`resolve` → `verifyAgentMd` | `peer.verifyAgentMd(signed).data?.status` |
@@ -559,8 +613,8 @@ const me = result.data.aid;
559
613
  const store = new AIDStore({ aunPath, encryptionSeed: '' });
560
614
  const result = await store.resolve('bob.aid.pub');
561
615
 
562
- if (result.ok && result.data.agentMd?.verification.status === 'verified') {
563
- console.log('对端可信:', result.data.agentMd.content);
616
+ if (result.ok && result.data.agent_md?.verification.status === 'verified') {
617
+ console.log('对端可信:', result.data.agent_md.content);
564
618
  }
565
619
  ```
566
620
 
@@ -568,7 +622,7 @@ if (result.ok && result.data.agentMd?.verification.status === 'verified') {
568
622
 
569
623
  ```typescript
570
624
  const store = new AIDStore({ aunPath, encryptionSeed: '' });
571
- const peer = (await store.load('bob.aid.pub')).data?.aid;
625
+ const peer = store.load('bob.aid.pub').data?.aid;
572
626
 
573
627
  if (peer?.isCertValid()) {
574
628
  const r = peer.verifyAgentMd(content);
@@ -597,7 +651,7 @@ if (!reg.ok) {
597
651
  }
598
652
 
599
653
  // Step 3: 加载身份用于后续操作
600
- const load = await store.load('alice.aid.pub');
654
+ const load = store.load('alice.aid.pub');
601
655
  const me = load.data!.aid;
602
656
  ```
603
657
 
@@ -605,13 +659,11 @@ const me = load.data!.aid;
605
659
 
606
660
  ```typescript
607
661
  const store = new AIDStore({ aunPath, encryptionSeed: '' });
608
- const list = await store.list();
662
+ const list = store.list();
609
663
  if (!list.ok) return;
610
664
 
611
- // 并发加载多个 AID 实例
612
- const aids = await Promise.all(
613
- list.data.identities.map(i => store.load(i.aid).then(r => r.data!.aid))
614
- );
665
+ // 并发加载多个 AID 实例(load 为同步,直接 map)
666
+ const aids = list.data.identities.map(i => store.load(i.aid).data!.aid);
615
667
 
616
668
  // 并发签名
617
669
  const signatures = aids.map(me => me.signAgentMd(content));
@@ -723,23 +775,36 @@ store.load(aid)
723
775
  class AUNClient {
724
776
  constructor(aid?: AID);
725
777
  loadIdentity(aid: AID): void; // 加载/重载身份,aid 必须 isPrivateKeyValid(),只在 NoIdentity 或 Closed 状态可调用
778
+ connect(opts?: ConnectionOptions): Promise<void>;
726
779
  setProtectedHeaders(headers: Record<string, string> | null): void; // 设置/清除实例级 protected_headers,随时可调
727
780
  }
781
+
782
+ type ConnectionOptions = {
783
+ auto_reconnect?: boolean; // 是否自动重连,默认 true
784
+ connect_timeout?: number; // 连接超时(秒),默认 5
785
+ retry_initial_delay?: number; // 最小退避间隔(秒),默认 1
786
+ retry_max_delay?: number; // 最大退避间隔(秒),默认 64
787
+ retry_max_attempts?: number; // 最大重试次数,0=无限,默认 0
788
+ heartbeat_interval?: number; // 心跳间隔(秒),默认 30
789
+ call_timeout?: number; // RPC 调用超时(秒),默认 35
790
+ };
728
791
  ```
729
792
 
730
793
  **说明**:
731
794
  - 构造时可选传入 AID 对象
732
795
  - 传入有效本地 AID(`isPrivateKeyValid() === true`)→ 直接进入 Standby 状态
733
796
  - 传入无效 AID 或不传 → 进入 NoIdentity 状态
797
+ - 所有配置(aunPath、verifySsl、rootCaPath、debug 等)通过 AID 对象传递,AUNClient 不单独接受配置参数,必须通过 AIDStore 创建的 AID 使用
734
798
  - `loadIdentity(aid)` 只在 NoIdentity 或 Closed 状态可调用
735
799
  - `loadIdentity` 传入的 AID 必须 `isPrivateKeyValid() === true`,否则抛 `InvalidIdentityError`
736
800
  - `deviceId` + `slotId` 由 AIDStore 管理,AUNClient 通过 AID 实例间接获取
801
+ - `connect(opts?)` 接受可选的 `ConnectionOptions`,用于控制连接行为(超时、重连退避等);gateway URL 和 token 来自 authenticate 缓存,不在 opts 中传入
737
802
  - `setProtectedHeaders(headers)` 随时可调,传 `null` 清除;设置后自动附加到所有 `call()`、`sendV2()`、`sendGroupV2()` 调用,无需在每次调用时传入
738
803
 
739
804
  **示例**:
740
805
  ```typescript
741
806
  const store = new AIDStore({ aunPath: '...', encryptionSeed: '...' });
742
- const me = (await store.load('alice.aid.pub')).data!.aid;
807
+ const me = store.load('alice.aid.pub').data!.aid;
743
808
  const client = new AUNClient(me);
744
809
 
745
810
  // 设置实例级 protected_headers
@@ -852,7 +917,7 @@ new AUNClient() new AUNClient(validAid)
852
917
 
853
918
  **关键说明**:
854
919
 
855
- - **Authenticated**:有 token,可调 `publishAgentMd()` / `uploadAgentMd()`,不需要长连接
920
+ - **Authenticated**:有 token,可调 `publishAgentMd()`,不需要长连接
856
921
  - **Connecting**:`connect()` 在 Standby 时自动先 authenticate(内部完成),在 Authenticated 时直接建连接
857
922
  - **RetryBackoff**:`isOnline === true`,SDK 仍认为自己应该在线,只是暂时等待。可读 `nextRetryAt`
858
923
  - **ConnectionFailed**:保留身份,可调 `connect()` 重新尝试
@@ -867,10 +932,10 @@ new AUNClient() new AUNClient(validAid)
867
932
  | **NoIdentity** | `loadIdentity(aid)` | Standby | aid 必须 `isPrivateKeyValid()` |
868
933
  | | `close()` | Closed | 幂等 |
869
934
  | **Standby** | `authenticate()` | Authenticated | 拿 token,不建长连接 |
870
- | | `connect({ gateway? })` | Connecting | 自动先 authenticate 再建连接 |
935
+ | | `connect(opts?)` | Connecting | 自动先 authenticate 再建连接 |
871
936
  | | `loadIdentity(aid)` | ❌ 抛 StateError | 仅 NoIdentity / Closed 可重载 |
872
937
  | | `close()` | Closed | 清除身份 |
873
- | **Authenticated** | `connect({ gateway? })` | Connecting | 直接建连接(已有 token) |
938
+ | **Authenticated** | `connect(opts?)` | Connecting | 直接建连接(已有 token) |
874
939
  | | `disconnect()` | Standby | 丢弃 token |
875
940
  | | `close()` | Closed | 清除身份 |
876
941
  | **Connecting** | 成功 | Ready | 自动推进 |
@@ -881,7 +946,7 @@ new AUNClient() new AUNClient(validAid)
881
946
  | | 网络断开 | RetryBackoff | 自动推进,启动退避 |
882
947
  | | `close()` | Closed | 清除身份 |
883
948
  | **RetryBackoff** | 退避到期 | Reconnecting | 自动推进 |
884
- | | `connect()` | Reconnecting | 跳过退避,立即重连 |
949
+ | | `connect(opts?)` | Reconnecting | 跳过退避,立即重连 |
885
950
  | | `disconnect()` | Standby | 取消重连 |
886
951
  | | `close()` | Closed | 清除身份 |
887
952
  | **Reconnecting** | 成功 | Ready | 自动推进 |
@@ -889,7 +954,7 @@ new AUNClient() new AUNClient(validAid)
889
954
  | | 失败(重连耗尽) | ConnectionFailed | 自动推进,记录 lastError |
890
955
  | | `disconnect()` | Standby | 取消重连 |
891
956
  | | `close()` | Closed | 清除身份 |
892
- | **ConnectionFailed** | `connect()` | Connecting | 重新尝试 |
957
+ | **ConnectionFailed** | `connect(opts?)` | Connecting | 重新尝试 |
893
958
  | | `disconnect()` | Standby | 放弃重试 |
894
959
  | | `close()` | Closed | 清除身份 |
895
960
  | **Closed** | `loadIdentity(aid)` | Standby | 重新激活 |
@@ -903,7 +968,7 @@ new AUNClient() new AUNClient(validAid)
903
968
  | **状态推进** |
904
969
  | `loadIdentity(aid)` | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ |
905
970
  | `authenticate()` | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
906
- | `connect({ gateway? })` | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ |
971
+ | `connect()` | ❌ | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ |
907
972
  | `disconnect()` | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
908
973
  | `close()` | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
909
974
  | **状态查询** |
@@ -933,14 +998,13 @@ new AUNClient() new AUNClient(validAid)
933
998
  | `off()` | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
934
999
  | **agent.md 上传**(需 token) |
935
1000
  | `publishAgentMd()` | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
936
- | `uploadAgentMd()` | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
937
1001
 
938
1002
  **图例**:
939
1003
  - ✅ 可调用
940
1004
  - ❌ 不可调用(抛 StateError)
941
1005
 
942
1006
  **说明**:
943
- - `publishAgentMd` / `uploadAgentMd` 要求至少 Authenticated(有 token)。Standby 状态下先调 `authenticate()`
1007
+ - `publishAgentMd` 要求至少 Authenticated(有 token)。Standby 状态下先调 `authenticate()`
944
1008
  - `disconnect()` 在 ConnectionFailed 状态也可调,从"放弃重试"语义回到 Standby
945
1009
  - 签名/验签操作直接用 `AID` 实例(`me.signAgentMd()`、`peer.verifyAgentMd()`),不在 AUNClient 上
946
1010
 
@@ -952,8 +1016,8 @@ new AUNClient() new AUNClient(validAid)
952
1016
  class AUNClient {
953
1017
  // ─── 基础状态 ─────────────────────────
954
1018
  get state(): ConnectionState;
955
- // 'no-identity' | 'standby' | 'authenticated' | 'connecting' | 'ready'
956
- // | 'retry-backoff' | 'reconnecting' | 'connection-failed' | 'closed'
1019
+ // 'no_identity' | 'standby' | 'authenticated' | 'connecting' | 'ready'
1020
+ // | 'retry_backoff' | 'reconnecting' | 'connection_failed' | 'closed'
957
1021
 
958
1022
  get currentAid(): AID | null;
959
1023
  get aunPath(): string | null;
@@ -972,12 +1036,12 @@ class AUNClient {
972
1036
  get gatewayHealth(): boolean | null;
973
1037
 
974
1038
  // ─── Capability Getters ─────────────────
975
- get hasIdentity(): boolean; // state !== 'no-identity' && state !== 'closed'
1039
+ get hasIdentity(): boolean; // state !== 'no_identity' && state !== 'closed'
976
1040
  get canSign(): boolean; // hasIdentity && currentAid.isPrivateKeyValid()
977
1041
  get canConnect(): boolean; // hasIdentity && state !== 'closed'
978
1042
  get canSend(): boolean; // state === 'ready'
979
1043
  get isReady(): boolean; // 同 canSend
980
- get isOnline(): boolean; // ready | retry-backoff | reconnecting
1044
+ get isOnline(): boolean; // ready | retry_backoff | reconnecting
981
1045
  get isClosed(): boolean; // state === 'closed'
982
1046
  }
983
1047
  ```
@@ -1005,9 +1069,9 @@ class AUNClient {
1005
1069
  │ ├─ 是 → call()
1006
1070
  │ └─ 否 → 看当前状态
1007
1071
  │ ├─ 'standby' / 'authenticated' → connect()
1008
- │ ├─ 'retry-backoff' → connect()(跳过退避立即重连)
1009
- │ ├─ 'connection-failed' → connect()(重新尝试)
1010
- │ └─ 'no-identity' / 'closed' → loadIdentity() 先
1072
+ │ ├─ 'retry_backoff' → connect()(跳过退避立即重连)
1073
+ │ ├─ 'connection_failed' → connect()(重新尝试)
1074
+ │ └─ 'no_identity' / 'closed' → loadIdentity() 先
1011
1075
 
1012
1076
  ├─ 主动断开 → disconnect()(任意连接相关状态都行)
1013
1077
 
@@ -1022,7 +1086,7 @@ class AUNClient {
1022
1086
 
1023
1087
  ```typescript
1024
1088
  const store = new AIDStore({ aunPath: '...', encryptionSeed: '...' });
1025
- const me = (await store.load('alice.aid.pub')).data!.aid;
1089
+ const me = store.load('alice.aid.pub').data!.aid;
1026
1090
  const client = new AUNClient(me); // → Standby
1027
1091
  await client.connect(); // Standby → Authenticated → Connecting → Ready
1028
1092
  // connect() 内部自动完成 authenticate(如果还没有 token)
@@ -1032,7 +1096,7 @@ await client.connect(); // Standby → Authenticated → Connecting
1032
1096
 
1033
1097
  ```typescript
1034
1098
  const store = new AIDStore({ aunPath: '...', encryptionSeed: '...' });
1035
- const me = (await store.load('alice.aid.pub')).data!.aid;
1099
+ const me = store.load('alice.aid.pub').data!.aid;
1036
1100
  const client = new AUNClient(me); // → Standby
1037
1101
 
1038
1102
  await client.authenticate(); // Standby → Authenticated
@@ -1057,15 +1121,15 @@ console.log('下次重连:', client.nextRetryInSeconds, '秒后');
1057
1121
  **场景 4:重连等待中应用想立即发消息**
1058
1122
 
1059
1123
  ```typescript
1060
- // 当前 state === 'retry-backoff'
1124
+ // 当前 state === 'retry_backoff'
1061
1125
  // 应用想立即发消息,不想等退避
1062
1126
 
1063
1127
  if (!client.canSend) {
1064
1128
  await client.connect(); // 跳过退避,立即进入 Reconnecting
1065
1129
  }
1066
1130
 
1067
- // 等待 Reconnecting → Ready,或监听 'state-change' 事件
1068
- client.on('state-change', ({ to }) => {
1131
+ // 等待 Reconnecting → Ready,或监听 'state_change' 事件
1132
+ client.on('state_change', ({ to }) => {
1069
1133
  if (to === 'ready') {
1070
1134
  client.call('message.send', {...});
1071
1135
  }
@@ -1075,7 +1139,7 @@ client.on('state-change', ({ to }) => {
1075
1139
  **场景 5:重连耗尽后手动重试**
1076
1140
 
1077
1141
  ```typescript
1078
- // state === 'connection-failed'
1142
+ // state === 'connection_failed'
1079
1143
  console.log('重连失败:', client.lastError, client.lastErrorCode);
1080
1144
 
1081
1145
  // 应用决定再试一次(身份还在)
@@ -1096,7 +1160,7 @@ await client.connect(); // Standby → Authenticated → Connecting → Read
1096
1160
 
1097
1161
  ```typescript
1098
1162
  await client.close(); // → Closed(身份清除)
1099
- const newMe = (await store.load('bob.aid.pub')).data!.aid;
1163
+ const newMe = store.load('bob.aid.pub').data!.aid;
1100
1164
  client.loadIdentity(newMe); // Closed → Standby(新身份)
1101
1165
  await client.connect(); // → Authenticated → Connecting → Ready
1102
1166
  ```
@@ -1106,7 +1170,7 @@ await client.connect(); // → Authenticated → Connecting →
1106
1170
  ```typescript
1107
1171
  // 应用启动时,预先认证以减少后续连接延迟
1108
1172
  const store = new AIDStore({ aunPath: '...', encryptionSeed: '...' });
1109
- const me = (await store.load('alice.aid.pub')).data!.aid;
1173
+ const me = store.load('alice.aid.pub').data!.aid;
1110
1174
  const client = new AUNClient(me);
1111
1175
  await client.authenticate(); // → Authenticated(提前拿好 token)
1112
1176
 
@@ -1134,14 +1198,14 @@ if (client.isOnline) {
1134
1198
  }
1135
1199
 
1136
1200
  if (!client.hasIdentity) {
1137
- client.loadIdentity((await store.load('alice.aid.pub')).data!.aid);
1201
+ client.loadIdentity(store.load('alice.aid.pub').data!.aid);
1138
1202
  }
1139
1203
  ```
1140
1204
 
1141
1205
  **RetryBackoff 状态下的常见模式**:
1142
1206
 
1143
1207
  ```typescript
1144
- if (client.state === 'retry-backoff') {
1208
+ if (client.state === 'retry_backoff') {
1145
1209
  console.log(`将在 ${client.nextRetryInSeconds} 秒后自动重连`);
1146
1210
  console.log(`已尝试 ${client.retryAttempt}/${client.retryMaxAttempts} 次`);
1147
1211
 
@@ -1275,6 +1339,7 @@ client.on('group.message_created', (msg) => {
1275
1339
  | | `rekey(aid)` | 是 | 密钥轮换并落盘 |
1276
1340
  | | `changeSeed(oldSeed, newSeed)` | 否 | 更换加密种子 |
1277
1341
  | | `diagnose(aid)` | 是 | 本地 + 远端状态对比 |
1342
+ | **资源管理** | `close()` | 否 | 释放内部 HTTP client 等资源 |
1278
1343
 
1279
1344
  ### 4.2 AID 操作表
1280
1345
 
@@ -1295,7 +1360,7 @@ client.on('group.message_created', (msg) => {
1295
1360
  | **构造** | `new AUNClient()` | 否 | — | → NoIdentity | 不传身份 |
1296
1361
  | | `new AUNClient(aid)` | 否 | — | → Standby | aid 必须 `isPrivateKeyValid()` |
1297
1362
  | **状态推进** | `loadIdentity(aid)` | 否 | NoIdentity \| Closed | → Standby | 加载/重载身份 |
1298
- | | `connect({ gateway? })` | 是 | Standby \| Authenticated \| RetryBackoff \| ConnectionFailed | → Connecting / Reconnecting | Standby 时自动先 authenticate |
1363
+ | | `connect(opts?)` | 是 | Standby \| Authenticated \| RetryBackoff \| ConnectionFailed | → Connecting / Reconnecting | Standby 时自动先 authenticate;可选 ConnectionOptions 控制连接行为;gateway URL 和 token 来自 authenticate 缓存,不在 opts 中传入 |
1299
1364
  | | `authenticate()` | 是 | Standby | → Authenticated | 拿 token,不建长连接 |
1300
1365
  | | `disconnect()` | 是 | Authenticated \| Connecting \| Ready \| RetryBackoff \| Reconnecting \| ConnectionFailed | → Standby | 主动断开 |
1301
1366
  | | `close()` | 否 | * | → Closed | 清除身份 + 资源 |
@@ -1313,7 +1378,7 @@ client.on('group.message_created', (msg) => {
1313
1378
  | | `canConnect` (getter) | 否 | — | — | hasIdentity 且非 Closed |
1314
1379
  | | `canSend` (getter) | 否 | — | — | state === 'ready' |
1315
1380
  | | `isReady` (getter) | 否 | — | — | 同 canSend |
1316
- | | `isOnline` (getter) | 否 | — | — | ready \| retry-backoff \| reconnecting |
1381
+ | | `isOnline` (getter) | 否 | — | — | ready \| retry_backoff \| reconnecting |
1317
1382
  | | `isClosed` (getter) | 否 | — | — | state === 'closed' |
1318
1383
  | **对端管理** | `lookupPeer(aid)` | 视缓存 | hasIdentity | — | 查缓存 → 无则解析 |
1319
1384
  | | `getPeer(aid)` | 否 | hasIdentity | — | 仅查缓存 |
@@ -1323,7 +1388,6 @@ client.on('group.message_created', (msg) => {
1323
1388
  | | `on(event, handler)` | 否 | hasIdentity | — | 事件订阅 |
1324
1389
  | | `off(event, handler)` | 否 | hasIdentity | — | 取消订阅 |
1325
1390
  | **agent.md 上传** | `publishAgentMd(content?)` | 是 | Authenticated \| Connecting \| Ready | — | 签名 + 上传 |
1326
- | | `uploadAgentMd(content)` | 是 | Authenticated \| Connecting \| Ready | — | 直接上传已签名内容 |
1327
1391
  | **配置** | `setProtectedHeaders(headers)` | 否 | * | — | 设置实例级 protected_headers,传 null 清除,随时可调 |
1328
1392
  | | `getProtectedHeaders()` | 否 | * | — | 读取当前实例级 protected_headers |
1329
1393
 
@@ -1331,7 +1395,7 @@ client.on('group.message_created', (msg) => {
1331
1395
 
1332
1396
  | 事件 | 触发时机 | 数据 |
1333
1397
  |------|---------|------|
1334
- | `state-change` | 状态变化 | `{ from, to }` |
1398
+ | `state_change` | 状态变化 | `{ from, to }` |
1335
1399
  | `message.received` | 收到 P2P 消息 | `{ from, payload, protected_headers?, context?, ... }` |
1336
1400
  | `group.message_created` | 收到群消息 | `{ from, group_id, payload, protected_headers?, context?, ... }` |
1337
1401
  | `message.recalled` | 消息被撤回 | `{ message_id, from, ... }` |
@@ -1407,7 +1471,7 @@ const store = new AIDStore({
1407
1471
  encryptionSeed: process.env.ENCRYPTION_SEED || ''
1408
1472
  });
1409
1473
 
1410
- const loadResult = await store.load('alice.aid.pub');
1474
+ const loadResult = store.load('alice.aid.pub');
1411
1475
  if (!loadResult.ok) {
1412
1476
  console.log('加载失败:', loadResult.error.code);
1413
1477
  return;
@@ -1435,7 +1499,7 @@ const store = new AIDStore({
1435
1499
  encryptionSeed: process.env.ENCRYPTION_SEED || ''
1436
1500
  });
1437
1501
 
1438
- const me = (await store.load('alice.aid.pub')).data!.aid;
1502
+ const me = store.load('alice.aid.pub').data!.aid;
1439
1503
  const client = new AUNClient(me);
1440
1504
 
1441
1505
  await client.connect(); // 自动完成认证 + 建立连接
@@ -1503,7 +1567,7 @@ if (verifyResult.ok && verifyResult.data.status === 'verified') {
1503
1567
  | `auth.fetchPeerCert({ aid })` | `AIDStore.resolve()` 内部自动完成 | ✅ |
1504
1568
  | `auth.signAgentMd(content, { aid })` | `aid.signAgentMd(content)` | ✅ |
1505
1569
  | `auth.verifyAgentMd(content, { aid, certPem })` | `aid.verifyAgentMd(content)` | ✅ |
1506
- | `auth.uploadAgentMd(content)` | `AUNClient.uploadAgentMd(content)` | ✅ |
1570
+ | `auth.uploadAgentMd(content)` | `AUNClient._uploadAgentMd(content)`(内部私有方法) | ✅ |
1507
1571
  | `auth.downloadAgentMd(aid)` | `AIDStore.fetchAgentMd(aid)` | ✅ |
1508
1572
  | `auth.headAgentMd(aid)` | `AIDStore.headAgentMd(aid)` | ✅ |
1509
1573
  | `auth.checkAid({ aid })` | `AIDStore.diagnose(aid)` | ✅ |
@@ -1517,7 +1581,7 @@ if (verifyResult.ok && verifyResult.data.status === 'verified') {
1517
1581
 
1518
1582
  | 当前方法 | 新归宿 | 迁移状态 |
1519
1583
  |---------|--------|:--------:|
1520
- | `client.connect(auth, opts)` | `AUNClient.connect({ gateway? })` | ✅ |
1584
+ | `client.connect(auth, opts)` | `AUNClient.connect()` | ✅ |
1521
1585
  | `client.disconnect()` | `AUNClient.disconnect()` | ✅ |
1522
1586
  | `client.close()` | `AUNClient.close()` | ✅ |
1523
1587
  | `client.call(method, params)` | `AUNClient.call(method, params)` | ✅ |
@@ -1628,6 +1692,6 @@ if (verifyResult.ok && verifyResult.data.status === 'verified') {
1628
1692
 
1629
1693
  ---
1630
1694
 
1631
- **文档版本**:v4.0
1632
- **最后更新**:2026-05-28
1695
+ **文档版本**:v4.2
1696
+ **最后更新**:2026-05-30
1633
1697