@agentunion/fastaun 0.5.31 → 0.5.33

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 (91) hide show
  1. package/CHANGELOG.md +69 -1
  2. package/_packed_docs/CHANGELOG.md +69 -1
  3. package/_packed_docs/sdk/0.5.32-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +350 -0
  4. package/_packed_docs/sdk/0.5.32-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +319 -0
  5. package/_packed_docs/sdk/0.5.33-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +316 -0
  6. package/_packed_docs/sdk/0.5.33-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +304 -0
  7. package/_packed_docs/sdk/09-storage-rpc-manual.md +33 -16
  8. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +12 -5
  9. package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +459 -0
  10. package/_packed_docs/sdk/AUN/344/272/213/344/273/266/345/217/221/345/270/203/350/256/242/351/230/205/345/274/200/345/217/221/347/247/273/346/244/215/346/214/207/345/215/227.md +554 -0
  11. package/_packed_docs/sdk/INDEX.md +27 -5
  12. package/_packed_docs/sdk//345/255/220AID/344/277/256/346/224/271agent.md/351/200/232/347/237/245Owner/345/234/272/346/231/257/346/214/207/345/215/227.md +234 -0
  13. package/dist/agent-md.d.ts +2 -1
  14. package/dist/agent-md.js +17 -0
  15. package/dist/agent-md.js.map +1 -1
  16. package/dist/client/control-messages.d.ts +22 -6
  17. package/dist/client/control-messages.js +210 -148
  18. package/dist/client/control-messages.js.map +1 -1
  19. package/dist/client/delivery.d.ts +3 -0
  20. package/dist/client/delivery.js +67 -3
  21. package/dist/client/delivery.js.map +1 -1
  22. package/dist/client/group-state.d.ts +3 -0
  23. package/dist/client/group-state.js +48 -14
  24. package/dist/client/group-state.js.map +1 -1
  25. package/dist/client/lifecycle.js +3 -2
  26. package/dist/client/lifecycle.js.map +1 -1
  27. package/dist/client/rpc-pipeline.d.ts +9 -3
  28. package/dist/client/rpc-pipeline.js +80 -27
  29. package/dist/client/rpc-pipeline.js.map +1 -1
  30. package/dist/client/v2-e2ee.d.ts +13 -1
  31. package/dist/client/v2-e2ee.js +32 -19
  32. package/dist/client/v2-e2ee.js.map +1 -1
  33. package/dist/client.d.ts +13 -5
  34. package/dist/client.js +121 -37
  35. package/dist/client.js.map +1 -1
  36. package/dist/group-fs.js +1 -1
  37. package/dist/group-fs.js.map +1 -1
  38. package/dist/index.d.ts +3 -1
  39. package/dist/index.js +1 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/ownership-workflow.d.ts +23 -3
  42. package/dist/ownership-workflow.js +39 -16
  43. package/dist/ownership-workflow.js.map +1 -1
  44. package/dist/pubsub/binding.d.ts +54 -0
  45. package/dist/pubsub/binding.js +343 -0
  46. package/dist/pubsub/binding.js.map +1 -0
  47. package/dist/pubsub/channel.d.ts +45 -0
  48. package/dist/pubsub/channel.js +137 -0
  49. package/dist/pubsub/channel.js.map +1 -0
  50. package/dist/pubsub/client.d.ts +93 -0
  51. package/dist/pubsub/client.js +318 -0
  52. package/dist/pubsub/client.js.map +1 -0
  53. package/dist/pubsub/credentials.d.ts +51 -0
  54. package/dist/pubsub/credentials.js +360 -0
  55. package/dist/pubsub/credentials.js.map +1 -0
  56. package/dist/pubsub/errors.d.ts +5 -0
  57. package/dist/pubsub/errors.js +6 -0
  58. package/dist/pubsub/errors.js.map +1 -0
  59. package/dist/pubsub/index.d.ts +48 -0
  60. package/dist/pubsub/index.js +152 -0
  61. package/dist/pubsub/index.js.map +1 -0
  62. package/dist/pubsub/scheduler.d.ts +58 -0
  63. package/dist/pubsub/scheduler.js +249 -0
  64. package/dist/pubsub/scheduler.js.map +1 -0
  65. package/dist/pubsub/service.d.ts +100 -0
  66. package/dist/pubsub/service.js +650 -0
  67. package/dist/pubsub/service.js.map +1 -0
  68. package/dist/pubsub/types.d.ts +119 -0
  69. package/dist/pubsub/types.js +2 -0
  70. package/dist/pubsub/types.js.map +1 -0
  71. package/dist/storage/lowlevel.d.ts +4 -2
  72. package/dist/storage/lowlevel.js +46 -7
  73. package/dist/storage/lowlevel.js.map +1 -1
  74. package/dist/storage/read-cache.d.ts +7 -3
  75. package/dist/storage/read-cache.js +149 -18
  76. package/dist/storage/read-cache.js.map +1 -1
  77. package/dist/storage/vfs.d.ts +5 -2
  78. package/dist/storage/vfs.js +13 -3
  79. package/dist/storage/vfs.js.map +1 -1
  80. package/dist/tools/cross-sdk-agent.d.ts +8 -2
  81. package/dist/tools/cross-sdk-agent.js +81 -16
  82. package/dist/tools/cross-sdk-agent.js.map +1 -1
  83. package/dist/tools/pubsub-actor.d.ts +27 -0
  84. package/dist/tools/pubsub-actor.js +260 -0
  85. package/dist/tools/pubsub-actor.js.map +1 -0
  86. package/dist/transport.d.ts +25 -1
  87. package/dist/transport.js +175 -10
  88. package/dist/transport.js.map +1 -1
  89. package/dist/version.d.ts +1 -1
  90. package/dist/version.js +1 -1
  91. package/package.json +1 -1
package/dist/client.d.ts CHANGED
@@ -12,14 +12,16 @@
12
12
  */
13
13
  import { AIDStore } from './aid-store.js';
14
14
  import { type Subscription, type EventHandler } from './events.js';
15
+ import { type RpcCallOptions } from './client/rpc-pipeline.js';
15
16
  import { type RiskStateEvent } from './risk-control.js';
16
17
  import { CollabClient } from './collab/client.js';
17
18
  import { DebugFacade, CredentialFacade, OrgFacade, GroupFacade, MailFacade, MessageFacade, StreamFacade } from './facades.js';
19
+ import { EventService } from './pubsub/index.js';
18
20
  import { StorageVFS } from './storage/vfs.js';
19
21
  import { type JsonObject, type JsonValue, type RpcParams, type RpcResult, ConnectionState } from './types.js';
20
22
  import { AID } from './aid.js';
21
23
  import { type OwnershipConsensusResult } from './ownership-v21.js';
22
- import { type OwnershipTaskResult } from './ownership-workflow.js';
24
+ import { type OwnershipRequestOptions, type OwnershipApprovalBatchResult, type OwnershipTaskResult } from './ownership-workflow.js';
23
25
  import { type CertificateMaterial } from './org-protocol.js';
24
26
  import { type RecordVerificationContext as SemanticRecordVerificationContext, type SemanticMessageVerificationContext } from './semantic-protocol.js';
25
27
  import type { SemanticPersistentState } from './semantic-facade.js';
@@ -102,6 +104,7 @@ export declare class AUNClient {
102
104
  private _credentialRenewalTimer;
103
105
  private _credentialRenewalAbort;
104
106
  private _credentialRenewalScan;
107
+ private _credentialRenewalBackground;
105
108
  private _nextCredentialRevocationSyncAt;
106
109
  private _getCredentialRenewal;
107
110
  _assertCredentialNotRevoked(credential: JsonObject, proofChain?: JsonObject[]): () => void;
@@ -266,6 +269,7 @@ export declare class AUNClient {
266
269
  private _storage?;
267
270
  private _collab?;
268
271
  private _message?;
272
+ private _eventServiceFacade?;
269
273
  private _debug?;
270
274
  private _mail?;
271
275
  private _group?;
@@ -284,6 +288,7 @@ export declare class AUNClient {
284
288
  /** AUN Collab 入口 */
285
289
  get collab(): CollabClient;
286
290
  get debug(): DebugFacade;
291
+ get EventService(): EventService;
287
292
  /** Message facade 入口 */
288
293
  get message(): MessageFacade;
289
294
  /** Group facade 入口 */
@@ -298,14 +303,14 @@ export declare class AUNClient {
298
303
  get_owner(): string | null;
299
304
  getOwnershipStatus(): Record<string, unknown>;
300
305
  get_ownership_status(): Record<string, unknown>;
301
- bindOwneraid(ownerAid: string): Promise<OwnershipTaskResult>;
302
- bindSubaid(subAid: string): Promise<OwnershipTaskResult>;
306
+ bindOwneraid(ownerAid: string, options?: OwnershipRequestOptions): Promise<OwnershipTaskResult>;
307
+ bindSubaid(subAid: string, options?: OwnershipRequestOptions): Promise<OwnershipTaskResult>;
303
308
  bindLocalSubaid(subClient: AUNClient): Promise<OwnershipTaskResult>;
304
309
  transferLocalSubaid(subClient: AUNClient, newOwnerClient: AUNClient): Promise<OwnershipTaskResult>;
305
310
  private _createOwnershipOperationClient;
306
311
  private _localOwnershipOperation;
307
312
  releaseSubaid(subAid: string): Promise<OwnershipTaskResult>;
308
- transferSubaid(subAid: string, newOwnerAid: string): Promise<OwnershipTaskResult>;
313
+ transferSubaid(subAid: string, newOwnerAid: string, options?: OwnershipRequestOptions): Promise<OwnershipTaskResult>;
309
314
  checkOwnershipConsensus(subAid?: string, force?: boolean): Promise<OwnershipConsensusResult>;
310
315
  private _checkOwnershipConsensusFresh;
311
316
  bindAid(subjectAid: string, options?: {
@@ -326,6 +331,9 @@ export declare class AUNClient {
326
331
  bind_owner(ownerAid: string, options?: Parameters<AUNClient['bindOwner']>[1]): Promise<RpcResult>;
327
332
  releaseOwnership(subjectAid: string): Promise<RpcResult>;
328
333
  release_ownership(subjectAid: string): Promise<RpcResult>;
334
+ acceptOwnershipRequests(operationIds: string[]): Promise<OwnershipApprovalBatchResult>;
335
+ rejectOwnershipRequests(operationIds: string[], reason?: string): Promise<OwnershipApprovalBatchResult>;
336
+ private _approveOwnershipRequests;
329
337
  acceptOwnershipRequest(operationId: string): Promise<OwnershipTaskResult>;
330
338
  rejectOwnershipRequest(operationId: string, reason?: string): Promise<OwnershipTaskResult>;
331
339
  private _handleOwnershipMessage;
@@ -400,7 +408,7 @@ export declare class AUNClient {
400
408
  * 发送 JSON-RPC 调用。
401
409
  * 自动处理内部方法限制、E2EE 加解密、客户端签名等。
402
410
  */
403
- call(method: string, params?: RpcParams): Promise<RpcResult>;
411
+ call(method: string, params?: RpcParams, options?: RpcCallOptions): Promise<RpcResult>;
404
412
  private _entityOwnershipGuard;
405
413
  private _prepareEntityOwnershipLifecycle;
406
414
  private _checkEntityOwnershipOnAccess;
package/dist/client.js CHANGED
@@ -42,6 +42,7 @@ import { RiskController } from './risk-control.js';
42
42
  import { ControlMessageCoordinator, messageClassOf } from './client/control-messages.js';
43
43
  import { CollabClient } from './collab/client.js';
44
44
  import { DebugFacade, CredentialFacade, OrgFacade, GroupFacade, MailFacade, MessageFacade, StreamFacade } from './facades.js';
45
+ import { EventService } from './pubsub/index.js';
45
46
  import { StorageVFS } from './storage/vfs.js';
46
47
  import { V2E2EECoordinator } from './client/v2-e2ee.js';
47
48
  import { GroupStateCoordinator } from './client/group-state.js';
@@ -53,7 +54,7 @@ import { AID } from './aid.js';
53
54
  import { certFingerprint, certMatchesFingerprint, normalizeFingerprintHex, publicKeyMatchesFingerprint } from './cert-utils.js';
54
55
  import { validateAgentMdCertificate, validateAgentMdDocument, validateAgentMdReadDocument } from './agent-md-schema.js';
55
56
  import { OwnershipFiles, OwnershipStorageAdapter, ownershipAid, ownershipFailure, ownershipSha256, parseOwnershipFile, signOwnershipFile } from './ownership-v21.js';
56
- import { OwnershipWorkflow, OWNERSHIP_SDK_MESSAGE_TYPE, parseOwnershipMessage } from './ownership-workflow.js';
57
+ import { ownershipApprovalBatch, OwnershipWorkflow, OWNERSHIP_SDK_MESSAGE_TYPE, parseOwnershipMessage } from './ownership-workflow.js';
57
58
  import { canonicalJson, createCredential, createMemberCredential, signMembershipBinding, digest, validateMembershipBinding, verifyMembershipBinding, verifyCredentialSignature, createRepresentationProof, verifyServiceEvent, buildRequestBinding, validateRequestBinding, CredentialRenewal } from './org-protocol.js';
58
59
  import { SemanticProtocolError } from './semantic-protocol.js';
59
60
  function isPromiseLike(value) {
@@ -522,7 +523,16 @@ export class AUNClient {
522
523
  currentType: () => this.getType(), assertCurrent: () => this._ownershipOperationGuard?.(),
523
524
  recoverRequest: (operationId) => this._recoverOwnershipRequest(operationId),
524
525
  send: (to, payload, messageId) => this.call('message.send', { to, encrypt: true, message_id: messageId, payload: payload }),
525
- emit: (event, payload) => { this._ownershipConsensusCache = new Map(); this._dispatcher.enqueue(event, payload); },
526
+ emit: (event, payload) => {
527
+ this._ownershipConsensusCache = new Map();
528
+ if (typeof payload.sub_aid === 'string') {
529
+ try {
530
+ this._agentMdManager.updateRecord(payload.sub_aid, (record) => { delete record.ownership_snapshot; });
531
+ }
532
+ catch { }
533
+ }
534
+ this._dispatcher.enqueue(event, payload);
535
+ },
526
536
  });
527
537
  }
528
538
  async _recoverOwnershipRequest(operationId) {
@@ -591,6 +601,7 @@ export class AUNClient {
591
601
  _credentialRenewalTimer = null;
592
602
  _credentialRenewalAbort = null;
593
603
  _credentialRenewalScan = Promise.resolve();
604
+ _credentialRenewalBackground = false;
594
605
  _nextCredentialRevocationSyncAt = 0;
595
606
  _getCredentialRenewal() {
596
607
  return this._credentialRenewal ??= new CredentialRenewal({
@@ -625,6 +636,8 @@ export class AUNClient {
625
636
  certificate: (aid, fingerprint, signedAt) => signedAt === undefined
626
637
  ? this._fetchServiceEventCertificate(aid, fingerprint) : this._fetchPeerCert(aid, fingerprint, undefined, signedAt),
627
638
  call: (method, params, onSent) => {
639
+ if (this._credentialRenewalBackground && params._rpc_background === undefined && params._rpc_background_kind === undefined)
640
+ params = { ...params, _rpc_background: true };
628
641
  if (!onSent)
629
642
  return this._rpcPipeline.call(method, params);
630
643
  const version = this._serviceEventIdentityVersion, aid = this._aid;
@@ -634,7 +647,7 @@ export class AUNClient {
634
647
  await onSent();
635
648
  });
636
649
  },
637
- send: (to, payload) => this.call('message.send', { to, encrypt: true, payload }),
650
+ send: (to, payload) => this.call('message.send', { to, encrypt: true, payload, ...(this._credentialRenewalBackground ? { _rpc_background: true } : {}) }),
638
651
  });
639
652
  }
640
653
  _assertCredentialNotRevoked(credential, proofChain) {
@@ -710,10 +723,18 @@ export class AUNClient {
710
723
  const task = this._credentialRenewalScan.then(async () => {
711
724
  if (!current())
712
725
  return;
726
+ if (this._transport._rateLimitRemainingMs() > 0)
727
+ return;
713
728
  const syncRevocations = this._sessionOptions.connection_kind !== 'short' && Date.now() >= this._nextCredentialRevocationSyncAt;
714
729
  if (syncRevocations)
715
730
  this._nextCredentialRevocationSyncAt = Date.now() + 3_600_000;
716
- await this._resumeCredentialRenewalAfterConnect(guard, syncRevocations);
731
+ this._credentialRenewalBackground = true;
732
+ try {
733
+ await this._resumeCredentialRenewalAfterConnect(guard, syncRevocations);
734
+ }
735
+ finally {
736
+ this._credentialRenewalBackground = false;
737
+ }
717
738
  });
718
739
  this._credentialRenewalScan = task.catch(() => { });
719
740
  await this._safeAsync(task);
@@ -1035,6 +1056,7 @@ export class AUNClient {
1035
1056
  _storage;
1036
1057
  _collab;
1037
1058
  _message;
1059
+ _eventServiceFacade;
1038
1060
  _debug;
1039
1061
  _mail;
1040
1062
  _group;
@@ -1275,6 +1297,11 @@ export class AUNClient {
1275
1297
  });
1276
1298
  return this._debug;
1277
1299
  }
1300
+ get EventService() {
1301
+ if (!this._eventServiceFacade)
1302
+ this._eventServiceFacade = new EventService(this);
1303
+ return this._eventServiceFacade;
1304
+ }
1278
1305
  /** Message facade 入口 */
1279
1306
  get message() {
1280
1307
  if (!this._message)
@@ -1315,8 +1342,8 @@ export class AUNClient {
1315
1342
  get_ownership_status() {
1316
1343
  return this.getOwnershipStatus();
1317
1344
  }
1318
- async bindOwneraid(ownerAid) { return this._getOwnershipWorkflow().bindOwneraid(ownerAid); }
1319
- async bindSubaid(subAid) { return this._getOwnershipWorkflow().bindSubaid(subAid); }
1345
+ async bindOwneraid(ownerAid, options) { return this._getOwnershipWorkflow().bindOwneraid(ownerAid, options); }
1346
+ async bindSubaid(subAid, options) { return this._getOwnershipWorkflow().bindSubaid(subAid, options); }
1320
1347
  async bindLocalSubaid(subClient) { return this._localOwnershipOperation(subClient); }
1321
1348
  async transferLocalSubaid(subClient, newOwnerClient) { return this._localOwnershipOperation(subClient, newOwnerClient); }
1322
1349
  _createOwnershipOperationClient(slotId) {
@@ -1330,8 +1357,8 @@ export class AUNClient {
1330
1357
  }
1331
1358
  async _localOwnershipOperation(sub, next) {
1332
1359
  const sources = [this, sub, ...(next ? [next] : [])];
1333
- if (sources.some((source, index) => !(source instanceof AUNClient) || !source._currentAid?.isPrivateKeyValid() || !source._currentAid.isCertValid() || !source._currentAid.privateKeyPem || source._currentAid.aid !== source._aid || (index === 1 ? source.getType() !== 'agent' : !['human', 'agent'].includes(source.getType()))) || new Set(sources.map((source) => source._aid)).size !== sources.length)
1334
- throw ownershipFailure('forbidden', 'local ownership requires a distinct agent subaid and human or agent owners with private identities');
1360
+ if (sources.some((source, index) => !(source instanceof AUNClient) || !source._currentAid?.isPrivateKeyValid() || !source._currentAid.isCertValid() || !source._currentAid.privateKeyPem || source._currentAid.aid !== source._aid || (index === 1 ? ['human', 'group', 'org'].includes(source.getType()) : !['human', 'agent'].includes(source.getType()))) || new Set(sources.map((source) => source._aid)).size !== sources.length)
1361
+ throw ownershipFailure('forbidden', 'local ownership requires a distinct non-human subaid outside group/org lifecycles and human or agent owners with private identities');
1335
1362
  const identities = sources.map((source) => [source._aid, source._currentAid, source._serviceEventIdentityVersion]);
1336
1363
  const guard = () => { if (sources.some((source, index) => source._aid !== identities[index][0] || source._currentAid !== identities[index][1] || source._serviceEventIdentityVersion !== identities[index][2]))
1337
1364
  throw ownershipFailure('conflict', 'local ownership source identity changed'); };
@@ -1343,8 +1370,8 @@ export class AUNClient {
1343
1370
  throw ownershipFailure('forbidden', 'local ownership requires a published agent document');
1344
1371
  const verified = await source._getOwnershipFiles().verifyFile(document.content, 'agent', source._aid);
1345
1372
  guard();
1346
- if ((index === 1 ? verified.frontmatter.type !== 'agent' : typeof verified.frontmatter.type !== 'string' || !['human', 'agent'].includes(verified.frontmatter.type)))
1347
- throw ownershipFailure('forbidden', 'local ownership requires an agent subaid and human or agent owners');
1373
+ if (typeof verified.frontmatter.type !== 'string' || !verified.frontmatter.type.trim() || (index === 1 ? ['human', 'group', 'org'].includes(verified.frontmatter.type) : !['human', 'agent'].includes(verified.frontmatter.type)))
1374
+ throw ownershipFailure('forbidden', 'local ownership requires a non-human subaid outside group/org lifecycles and human or agent owners');
1348
1375
  }
1349
1376
  const slot = `ownership-${crypto.randomUUID()}`, clients = [];
1350
1377
  try {
@@ -1365,24 +1392,34 @@ export class AUNClient {
1365
1392
  }
1366
1393
  }
1367
1394
  async releaseSubaid(subAid) { return this._getOwnershipWorkflow().releaseSubaid(subAid); }
1368
- async transferSubaid(subAid, newOwnerAid) { return this._getOwnershipWorkflow().transferSubaid(subAid, newOwnerAid); }
1395
+ async transferSubaid(subAid, newOwnerAid, options) { return this._getOwnershipWorkflow().transferSubaid(subAid, newOwnerAid, options); }
1369
1396
  async checkOwnershipConsensus(subAid, force = false) {
1370
1397
  const target = ownershipAid(subAid ?? this._aid, 'sub_aid');
1371
- const record = this._agentMdManager.loadRecord(target);
1398
+ const manager = this._agentMdManager;
1399
+ const record = manager.loadRecord(target);
1372
1400
  const observedEtag = String(record?.remote_etag ?? '');
1401
+ const observation = { root: manager.root, etag: observedEtag, version: Number(record?.observation_version ?? 0), content_hash: typeof record?.content === 'string' ? ownershipSha256(record.content) : '' };
1373
1402
  const cache = this._ownershipConsensusCache ??= new Map();
1374
1403
  const cached = cache.get(target);
1375
1404
  if (!force && cached?.result.status === 'consensus' && record?.remote_status !== 'missing'
1376
- && (observedEtag === cached.observedEtag || observedEtag === cached.result.agent_md_etag)) {
1405
+ && (observedEtag === cached.observedEtag || observedEtag === cached.result.agent_md_etag)
1406
+ && (typeof record?.content !== 'string' || ownershipSha256(record.content) === cached.result.agent_md_sha256)) {
1377
1407
  cached.observedEtag = observedEtag;
1378
1408
  return { ...cached.result };
1379
1409
  }
1410
+ if (!force && !cached) {
1411
+ const local = manager.localOwnershipConsensus(target, record);
1412
+ if (local) {
1413
+ cache.set(target, { observedEtag, result: local });
1414
+ return { ...local };
1415
+ }
1416
+ }
1380
1417
  cache.delete(target);
1381
1418
  const result = { status: 'unavailable', sub_aid: target, owner_aid: null, relation_version: 0, lock: 'unlocked', agent_md_etag: '', agent_md_sha256: '' };
1382
1419
  const entry = { observedEtag, result: { ...result } };
1383
1420
  cache.set(target, entry);
1384
1421
  try {
1385
- const snapshot = await this._agentMdManager.readOwnershipFresh(target);
1422
+ const snapshot = await manager.readOwnershipFresh(target);
1386
1423
  Object.assign(result, { relation_version: snapshot.relation_version, lock: snapshot.lock, agent_md_etag: snapshot.etag,
1387
1424
  agent_md_sha256: snapshot.exists ? ownershipSha256(snapshot.content) : '' });
1388
1425
  if (snapshot.ownership_status)
@@ -1402,8 +1439,13 @@ export class AUNClient {
1402
1439
  result.reason = error instanceof Error ? error.message : String(error);
1403
1440
  result.retryable = result.status === 'unavailable';
1404
1441
  }
1405
- if (cache.get(target) === entry)
1442
+ if (this._agentMdManager === manager && this._ownershipConsensusCache === cache && cache.get(target) === entry) {
1406
1443
  entry.result = { ...result };
1444
+ try {
1445
+ manager.cacheOwnershipSnapshot(target, result, observation);
1446
+ }
1447
+ catch { }
1448
+ }
1407
1449
  return result;
1408
1450
  }
1409
1451
  async _checkOwnershipConsensusFresh(subAid) {
@@ -1419,6 +1461,20 @@ export class AUNClient {
1419
1461
  async bind_owner(ownerAid, options = {}) { return this.bindOwner(ownerAid, options); }
1420
1462
  async releaseOwnership(subjectAid) { throw ownershipFailure('unsupported_protocol', 'legacy releaseOwnership is unsupported; use releaseSubaid'); }
1421
1463
  async release_ownership(subjectAid) { return this.releaseOwnership(subjectAid); }
1464
+ async acceptOwnershipRequests(operationIds) {
1465
+ return this._approveOwnershipRequests(operationIds);
1466
+ }
1467
+ async rejectOwnershipRequests(operationIds, reason) {
1468
+ return this._approveOwnershipRequests(operationIds, true, reason);
1469
+ }
1470
+ async _approveOwnershipRequests(operationIds, reject = false, reason) {
1471
+ const aid = this._aid, generation = this._serviceEventIdentityVersion;
1472
+ return ownershipApprovalBatch(operationIds, async (operationId) => {
1473
+ if (this._aid !== aid || this._serviceEventIdentityVersion !== generation)
1474
+ throw new StateError('ownership approval identity changed', { stringCode: 'conflict' });
1475
+ return reject ? this.rejectOwnershipRequest(operationId, reason) : this.acceptOwnershipRequest(operationId);
1476
+ });
1477
+ }
1422
1478
  async acceptOwnershipRequest(operationId) {
1423
1479
  return this._getOwnershipWorkflow().acceptOwnershipRequest(operationId);
1424
1480
  }
@@ -1904,14 +1960,14 @@ export class AUNClient {
1904
1960
  * 发送 JSON-RPC 调用。
1905
1961
  * 自动处理内部方法限制、E2EE 加解密、客户端签名等。
1906
1962
  */
1907
- async call(method, params) {
1963
+ async call(method, params, options) {
1908
1964
  const assertCurrent = ['group.transfer_owner', 'org.lifecycle.transfer', 'group.dissolve', 'org.lifecycle.dissolve'].includes(method) ? this._entityOwnershipGuard() : undefined;
1909
1965
  const recoverOwnership = ['group.transfer_owner', 'org.lifecycle.transfer', 'group.dissolve', 'org.lifecycle.dissolve'].includes(method) ? await this._prepareEntityOwnershipLifecycle(method, params ?? {}) : undefined;
1910
1966
  await this._checkEntityOwnershipOnAccess(method, params ?? {});
1911
1967
  const readIdentity = ['message.read', 'message.read_state', 'group.read', 'group.read_state'].includes(method)
1912
1968
  ? this._ensureReadStateIdentity() : null;
1913
1969
  try {
1914
- const result = await this._rpcPipeline.call(method, params, assertCurrent);
1970
+ const result = await (options === undefined ? this._rpcPipeline.call(method, params, assertCurrent) : this._rpcPipeline.call(method, params, assertCurrent, options));
1915
1971
  await this._safeAsync(this._getCredentialRenewal().observe(method, params ?? {}, result));
1916
1972
  if (readIdentity !== null && readIdentity === this._ensureReadStateIdentity())
1917
1973
  this._observeReadStateResult(method, result, params ?? {});
@@ -2010,6 +2066,9 @@ export class AUNClient {
2010
2066
  if (!pending?.private_key_pem || !pending.public_key_der_b64)
2011
2067
  return false;
2012
2068
  }
2069
+ const local = this._agentMdManager.localOwnershipConsensus(target, this._agentMdManager.loadRecord(target));
2070
+ if (local?.owner_aid === this._aid)
2071
+ return true;
2013
2072
  const result = await this._entityLifecycle(target, type);
2014
2073
  const data = result;
2015
2074
  const entity = (isJsonObject(data.group) ? data.group : isJsonObject(data.organization) ? data.organization : data);
@@ -2022,7 +2081,7 @@ export class AUNClient {
2022
2081
  return await existing;
2023
2082
  this._entityOwnershipChecks.set(`${identity}:${aid}`, task);
2024
2083
  }
2025
- const consensus = await this.checkOwnershipConsensus(aid, true);
2084
+ const consensus = await this.checkOwnershipConsensus(aid);
2026
2085
  if (consensus.status === 'consensus' && consensus.owner_aid === this._aid)
2027
2086
  return true;
2028
2087
  await this._completeEntityOwnership(aid, type, undefined, () => {
@@ -2183,12 +2242,19 @@ export class AUNClient {
2183
2242
  if (!aid)
2184
2243
  return;
2185
2244
  try {
2186
- const checked = await this._agentMdManager.check(aid, 0);
2187
- if (!checked.remote_found) {
2188
- await this._ensureInitialAgentMd();
2189
- }
2190
- else if (checked.in_sync === false) {
2191
- await this._agentMdManager.download(aid);
2245
+ const record = this._agentMdManager.loadRecord(aid);
2246
+ const verified = record?.verified_agent_md;
2247
+ const local = record?.content && record.remote_status !== 'missing' && record.remote_etag
2248
+ && (record.local_etag === record.remote_etag || record.verify_status === 'verified' && verified?.etag === record.remote_etag && verified.content_hash === record.local_etag
2249
+ || this._agentMdManager.localOwnershipConsensus(aid, record));
2250
+ if (!local) {
2251
+ const checked = await this._agentMdManager.check(aid, 0);
2252
+ if (!checked.remote_found) {
2253
+ await this._ensureInitialAgentMd();
2254
+ }
2255
+ else if (checked.in_sync === false) {
2256
+ await this._agentMdManager.download(aid);
2257
+ }
2192
2258
  }
2193
2259
  }
2194
2260
  catch (exc) {
@@ -3231,8 +3297,8 @@ export class AUNClient {
3231
3297
  const messageEvent = event === 'message.received' || event === 'message.recalled' || event === 'message.batch';
3232
3298
  const hadMessageConsumer = messageEvent && [...this._dispatcher._snapshotApplicationHandlers(['message.received', 'message.recalled', 'message.batch']).values()].some((handlers) => handlers.length > 0);
3233
3299
  const result = this._dispatcher.subscribe(event, handler);
3234
- if (messageEvent) {
3235
- if (this._p2pPeerPullEnabled && !hadMessageConsumer)
3300
+ if (messageEvent || event === 'group.message_created' || event === 'group.message_batch') {
3301
+ if (messageEvent && this._p2pPeerPullEnabled && !hadMessageConsumer)
3236
3302
  this._delivery.refreshPendingPeers();
3237
3303
  this._delivery.requestBackgroundPullRecovery();
3238
3304
  }
@@ -3376,7 +3442,7 @@ export class AUNClient {
3376
3442
  const errors = [];
3377
3443
  for (const entry of [...this._readStateQueries.values()]) {
3378
3444
  try {
3379
- const result = await this.call(entry.method, { ...entry.params });
3445
+ const result = await this.call(entry.method, { ...entry.params, _rpc_background: true });
3380
3446
  if (identity !== this._ensureReadStateIdentity())
3381
3447
  return;
3382
3448
  this._observeReadStateResult(entry.method, result, entry.params);
@@ -4386,7 +4452,7 @@ export class AUNClient {
4386
4452
  const seen = new Set();
4387
4453
  do {
4388
4454
  if (response === undefined) {
4389
- response = await this.call('group.list_my_invites', cursor ? { cursor } : {});
4455
+ response = await this.call('group.list_my_invites', { ...(cursor ? { cursor } : {}), _rpc_background: true });
4390
4456
  }
4391
4457
  let items = [];
4392
4458
  let nextCursor = '';
@@ -4500,6 +4566,7 @@ export class AUNClient {
4500
4566
  const tStart = Date.now();
4501
4567
  connectionOwner ??= this._connectAbort ?? undefined;
4502
4568
  this._lifecycle.assertConnectionAttemptOwner(connectionOwner);
4569
+ this._controlMessageCoordinator?.close();
4503
4570
  const gatewayUrl = this._resolveGateway(params);
4504
4571
  this._gatewayUrl = gatewayUrl;
4505
4572
  this._slotId = String(params.slot_id ?? '');
@@ -4512,7 +4579,7 @@ export class AUNClient {
4512
4579
  delete capabilities.message_classes_v1;
4513
4580
  if (typeof this._tokenStore.updateInstanceState === 'function') {
4514
4581
  capabilities.message_classes_v2 = { p2p: ['normal', 'control', 'sdk_control'], group: ['normal', 'control'] };
4515
- capabilities.sdk_control_protocols = { 'aun.agent_md.changed': [1] };
4582
+ capabilities.sdk_control_protocols = { 'aun.agent_md.changed': [1], 'aun.pubsub': [1] };
4516
4583
  }
4517
4584
  else {
4518
4585
  delete capabilities.message_classes_v2;
@@ -4657,8 +4724,6 @@ export class AUNClient {
4657
4724
  else {
4658
4725
  this._clientLog.debug('V2 session init deferred for short connection');
4659
4726
  }
4660
- this._controlMessages().close();
4661
- this._safeAsync(this._controlMessages().recover());
4662
4727
  this._agentMdChanges?.close();
4663
4728
  this._agentMdChanges = new AgentMdChangeCoordinator(this);
4664
4729
  // connect/reconnect 成功后自动触发一次 P2P message.v2.pull,补齐离线期间积压
@@ -4672,6 +4737,10 @@ export class AUNClient {
4672
4737
  this._entityOwnershipChecks.clear();
4673
4738
  if (!this._ownershipOperation)
4674
4739
  this._safeAsync(this._checkIdentityAdmissionAfterConnect());
4740
+ this._safeAsync(this._delivery.restoreMessageClassPulls());
4741
+ if (!isShortConnection && backgroundSyncEnabled && this._v2Session) {
4742
+ this._safeAsync(this._v2AutoConfirmPendingProposals());
4743
+ }
4675
4744
  this._clientLog.debug(`_connectOnce exit: elapsed=${Date.now() - tStart}ms gateway=${gatewayUrl}, aid=${this._aid ?? ''}`);
4676
4745
  }
4677
4746
  catch (err) {
@@ -4823,8 +4892,8 @@ export class AUNClient {
4823
4892
  async _getV2SenderPubDer(fromAid, senderDeviceId, certFingerprint) {
4824
4893
  return await this._v2E2EE.getV2SenderPubDer(fromAid, senderDeviceId, certFingerprint);
4825
4894
  }
4826
- async _fetchV2SenderIKOnce(fromAid, senderDeviceId, groupId, certFingerprint) {
4827
- return await this._v2E2EE.fetchSenderIKOnce(fromAid, senderDeviceId, groupId, certFingerprint);
4895
+ async _fetchV2SenderIKOnce(fromAid, senderDeviceId, groupId, certFingerprint, rpcOptions) {
4896
+ return await this._v2E2EE.fetchSenderIKOnce(fromAid, senderDeviceId, groupId, certFingerprint, ...(rpcOptions ? [rpcOptions] : []));
4828
4897
  }
4829
4898
  _cacheV2PeerIKFromDevice(dev, fallbackAid = '') {
4830
4899
  const session = this._v2Session;
@@ -4885,7 +4954,9 @@ export class AUNClient {
4885
4954
  return await this._v2E2EE.ackGroupV2(groupId, upToSeq, groupAid);
4886
4955
  }
4887
4956
  /** 解密单条 V2 pull 消息。缺 sender IK 时先入 pending,后台补齐后重试。 */
4888
- async _decryptV2Message(msg, allowPending = true, emitUndecryptable = true, rotateKeys = true, observeAgentMd = true, deferStatus, deferKeyFetch = false, source = 'pull', deferredEffects) {
4957
+ async _decryptV2Message(msg, allowPending = true, emitUndecryptable = true, rotateKeys = true, observeAgentMd = true, deferStatus, deferKeyFetch = false, source = 'pull', deferredEffects, rpcOptions) {
4958
+ if (rpcOptions?.deadline !== undefined && rpcOptions.deadline <= Date.now())
4959
+ return null;
4889
4960
  const session = this._v2Session;
4890
4961
  if (!session)
4891
4962
  return null;
@@ -5000,9 +5071,11 @@ export class AUNClient {
5000
5071
  const senderDeviceId = String(aad.from_device ?? '');
5001
5072
  const senderCertFingerprint = String(envelope.sender_cert_fingerprint ?? '').trim().toLowerCase();
5002
5073
  let senderPubDer = await this._getV2SenderPubDer(fromAid, senderDeviceId, senderCertFingerprint);
5074
+ if (rpcOptions?.deadline !== undefined && rpcOptions.deadline <= Date.now())
5075
+ return null;
5003
5076
  if (!senderPubDer && !deferKeyFetch) {
5004
5077
  this._clientLog.warn(`V2 decrypt: no sender IK for ${fromAid} device=${senderDeviceId}`);
5005
- senderPubDer = await this._fetchV2SenderIKOnce(fromAid, senderDeviceId, groupIdForKeys, senderCertFingerprint);
5078
+ senderPubDer = await this._fetchV2SenderIKOnce(fromAid, senderDeviceId, groupIdForKeys, senderCertFingerprint, ...(rpcOptions ? [rpcOptions] : []));
5006
5079
  }
5007
5080
  if (!senderPubDer) {
5008
5081
  if (allowPending || deferStatus) {
@@ -5334,7 +5407,7 @@ export class AUNClient {
5334
5407
  }
5335
5408
  }
5336
5409
  /** 发现并缓存全部 Gateway 候选,供首连和自动重连故障转移使用。 */
5337
- async _resolveGatewayCandidatesForAid(aid, fresh = false, reconnectOwner) {
5410
+ async _resolveGatewayCandidatesForAid(aid, fresh = false, reconnectOwner, connectionOwner) {
5338
5411
  const resolvedAid = String(aid ?? this._aid ?? '').trim();
5339
5412
  if (!resolvedAid) {
5340
5413
  throw new StateError('gateway discovery requires a loaded AID');
@@ -5348,7 +5421,8 @@ export class AUNClient {
5348
5421
  const discoveryIsCurrent = () => (this._discovery === discovery
5349
5422
  && this._tokenStore === tokenStore
5350
5423
  && !this._closing
5351
- && (!reconnectOwner || this._ownsReconnect(reconnectOwner)));
5424
+ && (!reconnectOwner || this._ownsReconnect(reconnectOwner))
5425
+ && (!connectionOwner || this._lifecycle.ownsConnectionAttempt(connectionOwner)));
5352
5426
  if (!fresh && sameIssuer && this._gatewayCandidates.length > 0)
5353
5427
  return [...this._gatewayCandidates];
5354
5428
  if (!fresh && sameIssuer && this._gatewayUrl) {
@@ -5641,6 +5715,11 @@ export class AUNClient {
5641
5715
  scheduleNext();
5642
5716
  return;
5643
5717
  }
5718
+ const rateLimitRemaining = this._transport._rateLimitRemainingMs();
5719
+ if (rateLimitRemaining > 0) {
5720
+ scheduleNext(rateLimitRemaining);
5721
+ return;
5722
+ }
5644
5723
  let identity = this._identity;
5645
5724
  if (identity === null) {
5646
5725
  scheduleNext();
@@ -5678,6 +5757,11 @@ export class AUNClient {
5678
5757
  this._tokenRefreshFailures = 0;
5679
5758
  }
5680
5759
  catch (exc) {
5760
+ if (exc instanceof AUNError && (exc.code === -32429 || exc.code === -32029 || exc.code === 429 || exc.code === 4290)) {
5761
+ this._transport._observeRateLimit(exc);
5762
+ scheduleNext(this._transport._rateLimitRemainingMs());
5763
+ return;
5764
+ }
5681
5765
  if (exc instanceof AuthError) {
5682
5766
  if (authErrorRequiresRelogin(exc)) {
5683
5767
  this._clientLog.warn(`token refresh requires relogin, stopping refresh loop and triggering reconnect: ${exc.message}`);