@agentunion/fastaun 0.5.31 → 0.5.32

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 (81) hide show
  1. package/CHANGELOG.md +39 -1
  2. package/_packed_docs/CHANGELOG.md +39 -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/AUN_DOCS_GUIDE.md +12 -5
  6. 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
  7. 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
  8. package/_packed_docs/sdk/INDEX.md +27 -5
  9. 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
  10. package/dist/client/control-messages.d.ts +22 -6
  11. package/dist/client/control-messages.js +208 -146
  12. package/dist/client/control-messages.js.map +1 -1
  13. package/dist/client/delivery.d.ts +3 -0
  14. package/dist/client/delivery.js +67 -3
  15. package/dist/client/delivery.js.map +1 -1
  16. package/dist/client/group-state.d.ts +3 -0
  17. package/dist/client/group-state.js +48 -14
  18. package/dist/client/group-state.js.map +1 -1
  19. package/dist/client/lifecycle.js +3 -2
  20. package/dist/client/lifecycle.js.map +1 -1
  21. package/dist/client/rpc-pipeline.d.ts +9 -3
  22. package/dist/client/rpc-pipeline.js +53 -22
  23. package/dist/client/rpc-pipeline.js.map +1 -1
  24. package/dist/client/v2-e2ee.d.ts +13 -1
  25. package/dist/client/v2-e2ee.js +32 -19
  26. package/dist/client/v2-e2ee.js.map +1 -1
  27. package/dist/client.d.ts +6 -1
  28. package/dist/client.js +57 -21
  29. package/dist/client.js.map +1 -1
  30. package/dist/group-fs.js +1 -1
  31. package/dist/group-fs.js.map +1 -1
  32. package/dist/index.d.ts +2 -0
  33. package/dist/index.js +1 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/ownership-workflow.js +3 -3
  36. package/dist/ownership-workflow.js.map +1 -1
  37. package/dist/pubsub/binding.d.ts +54 -0
  38. package/dist/pubsub/binding.js +343 -0
  39. package/dist/pubsub/binding.js.map +1 -0
  40. package/dist/pubsub/channel.d.ts +45 -0
  41. package/dist/pubsub/channel.js +137 -0
  42. package/dist/pubsub/channel.js.map +1 -0
  43. package/dist/pubsub/client.d.ts +93 -0
  44. package/dist/pubsub/client.js +318 -0
  45. package/dist/pubsub/client.js.map +1 -0
  46. package/dist/pubsub/credentials.d.ts +51 -0
  47. package/dist/pubsub/credentials.js +360 -0
  48. package/dist/pubsub/credentials.js.map +1 -0
  49. package/dist/pubsub/errors.d.ts +5 -0
  50. package/dist/pubsub/errors.js +6 -0
  51. package/dist/pubsub/errors.js.map +1 -0
  52. package/dist/pubsub/index.d.ts +48 -0
  53. package/dist/pubsub/index.js +152 -0
  54. package/dist/pubsub/index.js.map +1 -0
  55. package/dist/pubsub/scheduler.d.ts +58 -0
  56. package/dist/pubsub/scheduler.js +249 -0
  57. package/dist/pubsub/scheduler.js.map +1 -0
  58. package/dist/pubsub/service.d.ts +100 -0
  59. package/dist/pubsub/service.js +650 -0
  60. package/dist/pubsub/service.js.map +1 -0
  61. package/dist/pubsub/types.d.ts +119 -0
  62. package/dist/pubsub/types.js +2 -0
  63. package/dist/pubsub/types.js.map +1 -0
  64. package/dist/storage/lowlevel.js +44 -7
  65. package/dist/storage/lowlevel.js.map +1 -1
  66. package/dist/storage/read-cache.d.ts +7 -3
  67. package/dist/storage/read-cache.js +137 -18
  68. package/dist/storage/read-cache.js.map +1 -1
  69. package/dist/storage/vfs.d.ts +1 -0
  70. package/dist/storage/vfs.js +11 -1
  71. package/dist/storage/vfs.js.map +1 -1
  72. package/dist/tools/cross-sdk-agent.d.ts +1 -1
  73. package/dist/tools/pubsub-actor.d.ts +27 -0
  74. package/dist/tools/pubsub-actor.js +260 -0
  75. package/dist/tools/pubsub-actor.js.map +1 -0
  76. package/dist/transport.d.ts +25 -1
  77. package/dist/transport.js +175 -10
  78. package/dist/transport.js.map +1 -1
  79. package/dist/version.d.ts +1 -1
  80. package/dist/version.js +1 -1
  81. package/package.json +1 -1
package/dist/client.d.ts CHANGED
@@ -12,9 +12,11 @@
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';
@@ -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 入口 */
@@ -400,7 +405,7 @@ export declare class AUNClient {
400
405
  * 发送 JSON-RPC 调用。
401
406
  * 自动处理内部方法限制、E2EE 加解密、客户端签名等。
402
407
  */
403
- call(method: string, params?: RpcParams): Promise<RpcResult>;
408
+ call(method: string, params?: RpcParams, options?: RpcCallOptions): Promise<RpcResult>;
404
409
  private _entityOwnershipGuard;
405
410
  private _prepareEntityOwnershipLifecycle;
406
411
  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';
@@ -591,6 +592,7 @@ export class AUNClient {
591
592
  _credentialRenewalTimer = null;
592
593
  _credentialRenewalAbort = null;
593
594
  _credentialRenewalScan = Promise.resolve();
595
+ _credentialRenewalBackground = false;
594
596
  _nextCredentialRevocationSyncAt = 0;
595
597
  _getCredentialRenewal() {
596
598
  return this._credentialRenewal ??= new CredentialRenewal({
@@ -625,6 +627,8 @@ export class AUNClient {
625
627
  certificate: (aid, fingerprint, signedAt) => signedAt === undefined
626
628
  ? this._fetchServiceEventCertificate(aid, fingerprint) : this._fetchPeerCert(aid, fingerprint, undefined, signedAt),
627
629
  call: (method, params, onSent) => {
630
+ if (this._credentialRenewalBackground && params._rpc_background === undefined && params._rpc_background_kind === undefined)
631
+ params = { ...params, _rpc_background: true };
628
632
  if (!onSent)
629
633
  return this._rpcPipeline.call(method, params);
630
634
  const version = this._serviceEventIdentityVersion, aid = this._aid;
@@ -634,7 +638,7 @@ export class AUNClient {
634
638
  await onSent();
635
639
  });
636
640
  },
637
- send: (to, payload) => this.call('message.send', { to, encrypt: true, payload }),
641
+ send: (to, payload) => this.call('message.send', { to, encrypt: true, payload, ...(this._credentialRenewalBackground ? { _rpc_background: true } : {}) }),
638
642
  });
639
643
  }
640
644
  _assertCredentialNotRevoked(credential, proofChain) {
@@ -710,10 +714,18 @@ export class AUNClient {
710
714
  const task = this._credentialRenewalScan.then(async () => {
711
715
  if (!current())
712
716
  return;
717
+ if (this._transport._rateLimitRemainingMs() > 0)
718
+ return;
713
719
  const syncRevocations = this._sessionOptions.connection_kind !== 'short' && Date.now() >= this._nextCredentialRevocationSyncAt;
714
720
  if (syncRevocations)
715
721
  this._nextCredentialRevocationSyncAt = Date.now() + 3_600_000;
716
- await this._resumeCredentialRenewalAfterConnect(guard, syncRevocations);
722
+ this._credentialRenewalBackground = true;
723
+ try {
724
+ await this._resumeCredentialRenewalAfterConnect(guard, syncRevocations);
725
+ }
726
+ finally {
727
+ this._credentialRenewalBackground = false;
728
+ }
717
729
  });
718
730
  this._credentialRenewalScan = task.catch(() => { });
719
731
  await this._safeAsync(task);
@@ -1035,6 +1047,7 @@ export class AUNClient {
1035
1047
  _storage;
1036
1048
  _collab;
1037
1049
  _message;
1050
+ _eventServiceFacade;
1038
1051
  _debug;
1039
1052
  _mail;
1040
1053
  _group;
@@ -1275,6 +1288,11 @@ export class AUNClient {
1275
1288
  });
1276
1289
  return this._debug;
1277
1290
  }
1291
+ get EventService() {
1292
+ if (!this._eventServiceFacade)
1293
+ this._eventServiceFacade = new EventService(this);
1294
+ return this._eventServiceFacade;
1295
+ }
1278
1296
  /** Message facade 入口 */
1279
1297
  get message() {
1280
1298
  if (!this._message)
@@ -1330,8 +1348,8 @@ export class AUNClient {
1330
1348
  }
1331
1349
  async _localOwnershipOperation(sub, next) {
1332
1350
  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');
1351
+ 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)
1352
+ throw ownershipFailure('forbidden', 'local ownership requires a distinct non-human subaid outside group/org lifecycles and human or agent owners with private identities');
1335
1353
  const identities = sources.map((source) => [source._aid, source._currentAid, source._serviceEventIdentityVersion]);
1336
1354
  const guard = () => { if (sources.some((source, index) => source._aid !== identities[index][0] || source._currentAid !== identities[index][1] || source._serviceEventIdentityVersion !== identities[index][2]))
1337
1355
  throw ownershipFailure('conflict', 'local ownership source identity changed'); };
@@ -1343,8 +1361,8 @@ export class AUNClient {
1343
1361
  throw ownershipFailure('forbidden', 'local ownership requires a published agent document');
1344
1362
  const verified = await source._getOwnershipFiles().verifyFile(document.content, 'agent', source._aid);
1345
1363
  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');
1364
+ 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)))
1365
+ throw ownershipFailure('forbidden', 'local ownership requires a non-human subaid outside group/org lifecycles and human or agent owners');
1348
1366
  }
1349
1367
  const slot = `ownership-${crypto.randomUUID()}`, clients = [];
1350
1368
  try {
@@ -1904,14 +1922,14 @@ export class AUNClient {
1904
1922
  * 发送 JSON-RPC 调用。
1905
1923
  * 自动处理内部方法限制、E2EE 加解密、客户端签名等。
1906
1924
  */
1907
- async call(method, params) {
1925
+ async call(method, params, options) {
1908
1926
  const assertCurrent = ['group.transfer_owner', 'org.lifecycle.transfer', 'group.dissolve', 'org.lifecycle.dissolve'].includes(method) ? this._entityOwnershipGuard() : undefined;
1909
1927
  const recoverOwnership = ['group.transfer_owner', 'org.lifecycle.transfer', 'group.dissolve', 'org.lifecycle.dissolve'].includes(method) ? await this._prepareEntityOwnershipLifecycle(method, params ?? {}) : undefined;
1910
1928
  await this._checkEntityOwnershipOnAccess(method, params ?? {});
1911
1929
  const readIdentity = ['message.read', 'message.read_state', 'group.read', 'group.read_state'].includes(method)
1912
1930
  ? this._ensureReadStateIdentity() : null;
1913
1931
  try {
1914
- const result = await this._rpcPipeline.call(method, params, assertCurrent);
1932
+ const result = await (options === undefined ? this._rpcPipeline.call(method, params, assertCurrent) : this._rpcPipeline.call(method, params, assertCurrent, options));
1915
1933
  await this._safeAsync(this._getCredentialRenewal().observe(method, params ?? {}, result));
1916
1934
  if (readIdentity !== null && readIdentity === this._ensureReadStateIdentity())
1917
1935
  this._observeReadStateResult(method, result, params ?? {});
@@ -3231,8 +3249,8 @@ export class AUNClient {
3231
3249
  const messageEvent = event === 'message.received' || event === 'message.recalled' || event === 'message.batch';
3232
3250
  const hadMessageConsumer = messageEvent && [...this._dispatcher._snapshotApplicationHandlers(['message.received', 'message.recalled', 'message.batch']).values()].some((handlers) => handlers.length > 0);
3233
3251
  const result = this._dispatcher.subscribe(event, handler);
3234
- if (messageEvent) {
3235
- if (this._p2pPeerPullEnabled && !hadMessageConsumer)
3252
+ if (messageEvent || event === 'group.message_created' || event === 'group.message_batch') {
3253
+ if (messageEvent && this._p2pPeerPullEnabled && !hadMessageConsumer)
3236
3254
  this._delivery.refreshPendingPeers();
3237
3255
  this._delivery.requestBackgroundPullRecovery();
3238
3256
  }
@@ -3376,7 +3394,7 @@ export class AUNClient {
3376
3394
  const errors = [];
3377
3395
  for (const entry of [...this._readStateQueries.values()]) {
3378
3396
  try {
3379
- const result = await this.call(entry.method, { ...entry.params });
3397
+ const result = await this.call(entry.method, { ...entry.params, _rpc_background: true });
3380
3398
  if (identity !== this._ensureReadStateIdentity())
3381
3399
  return;
3382
3400
  this._observeReadStateResult(entry.method, result, entry.params);
@@ -4386,7 +4404,7 @@ export class AUNClient {
4386
4404
  const seen = new Set();
4387
4405
  do {
4388
4406
  if (response === undefined) {
4389
- response = await this.call('group.list_my_invites', cursor ? { cursor } : {});
4407
+ response = await this.call('group.list_my_invites', { ...(cursor ? { cursor } : {}), _rpc_background: true });
4390
4408
  }
4391
4409
  let items = [];
4392
4410
  let nextCursor = '';
@@ -4500,6 +4518,7 @@ export class AUNClient {
4500
4518
  const tStart = Date.now();
4501
4519
  connectionOwner ??= this._connectAbort ?? undefined;
4502
4520
  this._lifecycle.assertConnectionAttemptOwner(connectionOwner);
4521
+ this._controlMessageCoordinator?.close();
4503
4522
  const gatewayUrl = this._resolveGateway(params);
4504
4523
  this._gatewayUrl = gatewayUrl;
4505
4524
  this._slotId = String(params.slot_id ?? '');
@@ -4512,7 +4531,7 @@ export class AUNClient {
4512
4531
  delete capabilities.message_classes_v1;
4513
4532
  if (typeof this._tokenStore.updateInstanceState === 'function') {
4514
4533
  capabilities.message_classes_v2 = { p2p: ['normal', 'control', 'sdk_control'], group: ['normal', 'control'] };
4515
- capabilities.sdk_control_protocols = { 'aun.agent_md.changed': [1] };
4534
+ capabilities.sdk_control_protocols = { 'aun.agent_md.changed': [1], 'aun.pubsub': [1] };
4516
4535
  }
4517
4536
  else {
4518
4537
  delete capabilities.message_classes_v2;
@@ -4657,8 +4676,6 @@ export class AUNClient {
4657
4676
  else {
4658
4677
  this._clientLog.debug('V2 session init deferred for short connection');
4659
4678
  }
4660
- this._controlMessages().close();
4661
- this._safeAsync(this._controlMessages().recover());
4662
4679
  this._agentMdChanges?.close();
4663
4680
  this._agentMdChanges = new AgentMdChangeCoordinator(this);
4664
4681
  // connect/reconnect 成功后自动触发一次 P2P message.v2.pull,补齐离线期间积压
@@ -4672,6 +4689,10 @@ export class AUNClient {
4672
4689
  this._entityOwnershipChecks.clear();
4673
4690
  if (!this._ownershipOperation)
4674
4691
  this._safeAsync(this._checkIdentityAdmissionAfterConnect());
4692
+ this._safeAsync(this._delivery.restoreMessageClassPulls());
4693
+ if (!isShortConnection && backgroundSyncEnabled && this._v2Session) {
4694
+ this._safeAsync(this._v2AutoConfirmPendingProposals());
4695
+ }
4675
4696
  this._clientLog.debug(`_connectOnce exit: elapsed=${Date.now() - tStart}ms gateway=${gatewayUrl}, aid=${this._aid ?? ''}`);
4676
4697
  }
4677
4698
  catch (err) {
@@ -4823,8 +4844,8 @@ export class AUNClient {
4823
4844
  async _getV2SenderPubDer(fromAid, senderDeviceId, certFingerprint) {
4824
4845
  return await this._v2E2EE.getV2SenderPubDer(fromAid, senderDeviceId, certFingerprint);
4825
4846
  }
4826
- async _fetchV2SenderIKOnce(fromAid, senderDeviceId, groupId, certFingerprint) {
4827
- return await this._v2E2EE.fetchSenderIKOnce(fromAid, senderDeviceId, groupId, certFingerprint);
4847
+ async _fetchV2SenderIKOnce(fromAid, senderDeviceId, groupId, certFingerprint, rpcOptions) {
4848
+ return await this._v2E2EE.fetchSenderIKOnce(fromAid, senderDeviceId, groupId, certFingerprint, ...(rpcOptions ? [rpcOptions] : []));
4828
4849
  }
4829
4850
  _cacheV2PeerIKFromDevice(dev, fallbackAid = '') {
4830
4851
  const session = this._v2Session;
@@ -4885,7 +4906,9 @@ export class AUNClient {
4885
4906
  return await this._v2E2EE.ackGroupV2(groupId, upToSeq, groupAid);
4886
4907
  }
4887
4908
  /** 解密单条 V2 pull 消息。缺 sender IK 时先入 pending,后台补齐后重试。 */
4888
- async _decryptV2Message(msg, allowPending = true, emitUndecryptable = true, rotateKeys = true, observeAgentMd = true, deferStatus, deferKeyFetch = false, source = 'pull', deferredEffects) {
4909
+ async _decryptV2Message(msg, allowPending = true, emitUndecryptable = true, rotateKeys = true, observeAgentMd = true, deferStatus, deferKeyFetch = false, source = 'pull', deferredEffects, rpcOptions) {
4910
+ if (rpcOptions?.deadline !== undefined && rpcOptions.deadline <= Date.now())
4911
+ return null;
4889
4912
  const session = this._v2Session;
4890
4913
  if (!session)
4891
4914
  return null;
@@ -5000,9 +5023,11 @@ export class AUNClient {
5000
5023
  const senderDeviceId = String(aad.from_device ?? '');
5001
5024
  const senderCertFingerprint = String(envelope.sender_cert_fingerprint ?? '').trim().toLowerCase();
5002
5025
  let senderPubDer = await this._getV2SenderPubDer(fromAid, senderDeviceId, senderCertFingerprint);
5026
+ if (rpcOptions?.deadline !== undefined && rpcOptions.deadline <= Date.now())
5027
+ return null;
5003
5028
  if (!senderPubDer && !deferKeyFetch) {
5004
5029
  this._clientLog.warn(`V2 decrypt: no sender IK for ${fromAid} device=${senderDeviceId}`);
5005
- senderPubDer = await this._fetchV2SenderIKOnce(fromAid, senderDeviceId, groupIdForKeys, senderCertFingerprint);
5030
+ senderPubDer = await this._fetchV2SenderIKOnce(fromAid, senderDeviceId, groupIdForKeys, senderCertFingerprint, ...(rpcOptions ? [rpcOptions] : []));
5006
5031
  }
5007
5032
  if (!senderPubDer) {
5008
5033
  if (allowPending || deferStatus) {
@@ -5334,7 +5359,7 @@ export class AUNClient {
5334
5359
  }
5335
5360
  }
5336
5361
  /** 发现并缓存全部 Gateway 候选,供首连和自动重连故障转移使用。 */
5337
- async _resolveGatewayCandidatesForAid(aid, fresh = false, reconnectOwner) {
5362
+ async _resolveGatewayCandidatesForAid(aid, fresh = false, reconnectOwner, connectionOwner) {
5338
5363
  const resolvedAid = String(aid ?? this._aid ?? '').trim();
5339
5364
  if (!resolvedAid) {
5340
5365
  throw new StateError('gateway discovery requires a loaded AID');
@@ -5348,7 +5373,8 @@ export class AUNClient {
5348
5373
  const discoveryIsCurrent = () => (this._discovery === discovery
5349
5374
  && this._tokenStore === tokenStore
5350
5375
  && !this._closing
5351
- && (!reconnectOwner || this._ownsReconnect(reconnectOwner)));
5376
+ && (!reconnectOwner || this._ownsReconnect(reconnectOwner))
5377
+ && (!connectionOwner || this._lifecycle.ownsConnectionAttempt(connectionOwner)));
5352
5378
  if (!fresh && sameIssuer && this._gatewayCandidates.length > 0)
5353
5379
  return [...this._gatewayCandidates];
5354
5380
  if (!fresh && sameIssuer && this._gatewayUrl) {
@@ -5641,6 +5667,11 @@ export class AUNClient {
5641
5667
  scheduleNext();
5642
5668
  return;
5643
5669
  }
5670
+ const rateLimitRemaining = this._transport._rateLimitRemainingMs();
5671
+ if (rateLimitRemaining > 0) {
5672
+ scheduleNext(rateLimitRemaining);
5673
+ return;
5674
+ }
5644
5675
  let identity = this._identity;
5645
5676
  if (identity === null) {
5646
5677
  scheduleNext();
@@ -5678,6 +5709,11 @@ export class AUNClient {
5678
5709
  this._tokenRefreshFailures = 0;
5679
5710
  }
5680
5711
  catch (exc) {
5712
+ if (exc instanceof AUNError && (exc.code === -32429 || exc.code === -32029 || exc.code === 429 || exc.code === 4290)) {
5713
+ this._transport._observeRateLimit(exc);
5714
+ scheduleNext(this._transport._rateLimitRemainingMs());
5715
+ return;
5716
+ }
5681
5717
  if (exc instanceof AuthError) {
5682
5718
  if (authErrorRequiresRelogin(exc)) {
5683
5719
  this._clientLog.warn(`token refresh requires relogin, stopping refresh loop and triggering reconnect: ${exc.message}`);