@agentunion/fastaun 0.5.32 → 0.5.34

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 (97) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/README.md +28 -26
  3. package/_packed_docs/CHANGELOG.md +58 -0
  4. package/_packed_docs/INDEX.md +17 -3
  5. package/_packed_docs/KITE_DOCS_GUIDE.md +10 -4
  6. package/_packed_docs/protocol/03-Gateway-/350/277/236/346/216/245/346/250/241/345/274/217.md +58 -8
  7. 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 +464 -0
  8. 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 +499 -0
  9. package/_packed_docs/sdk/0.5.34-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +133 -0
  10. package/_packed_docs/sdk/0.5.34-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +107 -0
  11. package/_packed_docs/sdk/01-/345/277/253/351/200/237/345/274/200/345/247/213.md +16 -13
  12. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +13 -1
  13. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +17 -7
  14. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +55 -14
  15. package/_packed_docs/sdk/09-collab-rpc-manual.md +48 -30
  16. package/_packed_docs/sdk/09-custody-api-manual.md +3 -3
  17. package/_packed_docs/sdk/09-group-rpc-manual.md +53 -6
  18. package/_packed_docs/sdk/09-message-rpc-manual.md +22 -0
  19. package/_packed_docs/sdk/09-meta-rpc-manual.md +2 -1
  20. package/_packed_docs/sdk/09-payload-reference.md +9 -8
  21. package/_packed_docs/sdk/09-proxy-rpc-manual.md +20 -14
  22. package/_packed_docs/sdk/09-storage-rpc-manual.md +1698 -1642
  23. package/_packed_docs/sdk/09-stream-rpc-manual.md +33 -20
  24. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +11 -9
  25. 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 +53 -28
  26. 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 +62 -28
  27. package/_packed_docs/sdk/INDEX.md +21 -9
  28. package/_packed_docs/sdk/README.md +11 -6
  29. package/dist/agent-md.d.ts +2 -1
  30. package/dist/agent-md.js +17 -0
  31. package/dist/agent-md.js.map +1 -1
  32. package/dist/auth.js +8 -2
  33. package/dist/auth.js.map +1 -1
  34. package/dist/client/control-messages.js +4 -4
  35. package/dist/client/control-messages.js.map +1 -1
  36. package/dist/client/delivery.d.ts +5 -0
  37. package/dist/client/delivery.js +146 -32
  38. package/dist/client/delivery.js.map +1 -1
  39. package/dist/client/lifecycle.js +3 -0
  40. package/dist/client/lifecycle.js.map +1 -1
  41. package/dist/client/rpc-budget.d.ts +21 -0
  42. package/dist/client/rpc-budget.js +82 -0
  43. package/dist/client/rpc-budget.js.map +1 -0
  44. package/dist/client/rpc-pipeline.d.ts +3 -0
  45. package/dist/client/rpc-pipeline.js +193 -65
  46. package/dist/client/rpc-pipeline.js.map +1 -1
  47. package/dist/client/sync-channels.d.ts +89 -0
  48. package/dist/client/sync-channels.js +489 -0
  49. package/dist/client/sync-channels.js.map +1 -0
  50. package/dist/client/v2-e2ee.d.ts +4 -1
  51. package/dist/client/v2-e2ee.js +401 -298
  52. package/dist/client/v2-e2ee.js.map +1 -1
  53. package/dist/client.d.ts +9 -4
  54. package/dist/client.js +125 -15
  55. package/dist/client.js.map +1 -1
  56. package/dist/index.d.ts +2 -2
  57. package/dist/index.js.map +1 -1
  58. package/dist/ownership-workflow.d.ts +23 -3
  59. package/dist/ownership-workflow.js +36 -13
  60. package/dist/ownership-workflow.js.map +1 -1
  61. package/dist/pubsub/binding.js +14 -1
  62. package/dist/pubsub/binding.js.map +1 -1
  63. package/dist/pubsub/channel.d.ts +4 -0
  64. package/dist/pubsub/channel.js +26 -0
  65. package/dist/pubsub/channel.js.map +1 -1
  66. package/dist/pubsub/client.d.ts +9 -0
  67. package/dist/pubsub/client.js +154 -31
  68. package/dist/pubsub/client.js.map +1 -1
  69. package/dist/pubsub/credentials.d.ts +3 -0
  70. package/dist/pubsub/credentials.js +57 -20
  71. package/dist/pubsub/credentials.js.map +1 -1
  72. package/dist/pubsub/index.d.ts +3 -0
  73. package/dist/pubsub/index.js +69 -53
  74. package/dist/pubsub/index.js.map +1 -1
  75. package/dist/pubsub/service.d.ts +3 -0
  76. package/dist/pubsub/service.js +167 -12
  77. package/dist/pubsub/service.js.map +1 -1
  78. package/dist/pubsub/types.d.ts +2 -0
  79. package/dist/storage/lowlevel.d.ts +7 -3
  80. package/dist/storage/lowlevel.js +15 -0
  81. package/dist/storage/lowlevel.js.map +1 -1
  82. package/dist/storage/read-cache.js +12 -0
  83. package/dist/storage/read-cache.js.map +1 -1
  84. package/dist/storage/types.d.ts +10 -0
  85. package/dist/storage/types.js.map +1 -1
  86. package/dist/storage/vfs.d.ts +7 -3
  87. package/dist/storage/vfs.js +2 -2
  88. package/dist/storage/vfs.js.map +1 -1
  89. package/dist/tools/cross-sdk-agent.d.ts +62 -6
  90. package/dist/tools/cross-sdk-agent.js +169 -37
  91. package/dist/tools/cross-sdk-agent.js.map +1 -1
  92. package/dist/transport.d.ts +12 -0
  93. package/dist/transport.js +91 -6
  94. package/dist/transport.js.map +1 -1
  95. package/dist/version.d.ts +1 -1
  96. package/dist/version.js +1 -1
  97. package/package.json +1 -1
package/dist/client.d.ts CHANGED
@@ -21,7 +21,7 @@ import { StorageVFS } from './storage/vfs.js';
21
21
  import { type JsonObject, type JsonValue, type RpcParams, type RpcResult, ConnectionState } from './types.js';
22
22
  import { AID } from './aid.js';
23
23
  import { type OwnershipConsensusResult } from './ownership-v21.js';
24
- import { type OwnershipTaskResult } from './ownership-workflow.js';
24
+ import { type OwnershipRequestOptions, type OwnershipApprovalBatchResult, type OwnershipTaskResult } from './ownership-workflow.js';
25
25
  import { type CertificateMaterial } from './org-protocol.js';
26
26
  import { type RecordVerificationContext as SemanticRecordVerificationContext, type SemanticMessageVerificationContext } from './semantic-protocol.js';
27
27
  import type { SemanticPersistentState } from './semantic-facade.js';
@@ -263,6 +263,7 @@ export declare class AUNClient {
263
263
  private _peerDirectory;
264
264
  private _lifecycle;
265
265
  private _rpcPipeline;
266
+ private _syncChannelCoordinator;
266
267
  private _delivery;
267
268
  private _v2E2EE;
268
269
  private _groupState;
@@ -303,14 +304,14 @@ export declare class AUNClient {
303
304
  get_owner(): string | null;
304
305
  getOwnershipStatus(): Record<string, unknown>;
305
306
  get_ownership_status(): Record<string, unknown>;
306
- bindOwneraid(ownerAid: string): Promise<OwnershipTaskResult>;
307
- bindSubaid(subAid: string): Promise<OwnershipTaskResult>;
307
+ bindOwneraid(ownerAid: string, options?: OwnershipRequestOptions): Promise<OwnershipTaskResult>;
308
+ bindSubaid(subAid: string, options?: OwnershipRequestOptions): Promise<OwnershipTaskResult>;
308
309
  bindLocalSubaid(subClient: AUNClient): Promise<OwnershipTaskResult>;
309
310
  transferLocalSubaid(subClient: AUNClient, newOwnerClient: AUNClient): Promise<OwnershipTaskResult>;
310
311
  private _createOwnershipOperationClient;
311
312
  private _localOwnershipOperation;
312
313
  releaseSubaid(subAid: string): Promise<OwnershipTaskResult>;
313
- transferSubaid(subAid: string, newOwnerAid: string): Promise<OwnershipTaskResult>;
314
+ transferSubaid(subAid: string, newOwnerAid: string, options?: OwnershipRequestOptions): Promise<OwnershipTaskResult>;
314
315
  checkOwnershipConsensus(subAid?: string, force?: boolean): Promise<OwnershipConsensusResult>;
315
316
  private _checkOwnershipConsensusFresh;
316
317
  bindAid(subjectAid: string, options?: {
@@ -331,6 +332,9 @@ export declare class AUNClient {
331
332
  bind_owner(ownerAid: string, options?: Parameters<AUNClient['bindOwner']>[1]): Promise<RpcResult>;
332
333
  releaseOwnership(subjectAid: string): Promise<RpcResult>;
333
334
  release_ownership(subjectAid: string): Promise<RpcResult>;
335
+ acceptOwnershipRequests(operationIds: string[]): Promise<OwnershipApprovalBatchResult>;
336
+ rejectOwnershipRequests(operationIds: string[], reason?: string): Promise<OwnershipApprovalBatchResult>;
337
+ private _approveOwnershipRequests;
334
338
  acceptOwnershipRequest(operationId: string): Promise<OwnershipTaskResult>;
335
339
  rejectOwnershipRequest(operationId: string, reason?: string): Promise<OwnershipTaskResult>;
336
340
  private _handleOwnershipMessage;
@@ -359,6 +363,7 @@ export declare class AUNClient {
359
363
  lookupPeer(aid: string, certFingerprint?: string | null): Promise<AID>;
360
364
  peers(): AID[];
361
365
  /** transport 的 meta observer:吸收 gateway 注入的 _meta 字段。失败不影响业务。 */
366
+ private _historyChannels;
362
367
  private _observeRpcMeta;
363
368
  isGroupIndexStale(groupAid: string): boolean;
364
369
  markGroupIndexFresh(groupAid: string, options: {
package/dist/client.js CHANGED
@@ -26,6 +26,7 @@ import { AUNLogger } from './logger.js';
26
26
  import { normalizeGroupId } from './group-id.js';
27
27
  import { validateAIDFormat, validateGroupIDFormat } from './validators.js';
28
28
  import { RPCTransport } from './transport.js';
29
+ import { SyncChannels } from './client/sync-channels.js';
29
30
  import { AuthFlow } from './auth.js';
30
31
  import { AgentMdManager, buildDefaultAgentMd, updateOwnershipAgentMd } from './agent-md.js';
31
32
  import { AgentMdChangeCoordinator } from './agent-md-changes.js';
@@ -54,7 +55,7 @@ import { AID } from './aid.js';
54
55
  import { certFingerprint, certMatchesFingerprint, normalizeFingerprintHex, publicKeyMatchesFingerprint } from './cert-utils.js';
55
56
  import { validateAgentMdCertificate, validateAgentMdDocument, validateAgentMdReadDocument } from './agent-md-schema.js';
56
57
  import { OwnershipFiles, OwnershipStorageAdapter, ownershipAid, ownershipFailure, ownershipSha256, parseOwnershipFile, signOwnershipFile } from './ownership-v21.js';
57
- import { OwnershipWorkflow, OWNERSHIP_SDK_MESSAGE_TYPE, parseOwnershipMessage } from './ownership-workflow.js';
58
+ import { ownershipApprovalBatch, OwnershipWorkflow, OWNERSHIP_SDK_MESSAGE_TYPE, parseOwnershipMessage } from './ownership-workflow.js';
58
59
  import { canonicalJson, createCredential, createMemberCredential, signMembershipBinding, digest, validateMembershipBinding, verifyMembershipBinding, verifyCredentialSignature, createRepresentationProof, verifyServiceEvent, buildRequestBinding, validateRequestBinding, CredentialRenewal } from './org-protocol.js';
59
60
  import { SemanticProtocolError } from './semantic-protocol.js';
60
61
  function isPromiseLike(value) {
@@ -523,7 +524,16 @@ export class AUNClient {
523
524
  currentType: () => this.getType(), assertCurrent: () => this._ownershipOperationGuard?.(),
524
525
  recoverRequest: (operationId) => this._recoverOwnershipRequest(operationId),
525
526
  send: (to, payload, messageId) => this.call('message.send', { to, encrypt: true, message_id: messageId, payload: payload }),
526
- emit: (event, payload) => { this._ownershipConsensusCache = new Map(); this._dispatcher.enqueue(event, payload); },
527
+ emit: (event, payload) => {
528
+ this._ownershipConsensusCache = new Map();
529
+ if (typeof payload.sub_aid === 'string') {
530
+ try {
531
+ this._agentMdManager.updateRecord(payload.sub_aid, (record) => { delete record.ownership_snapshot; });
532
+ }
533
+ catch { }
534
+ }
535
+ this._dispatcher.enqueue(event, payload);
536
+ },
527
537
  });
528
538
  }
529
539
  async _recoverOwnershipRequest(operationId) {
@@ -1041,6 +1051,7 @@ export class AUNClient {
1041
1051
  _peerDirectory;
1042
1052
  _lifecycle;
1043
1053
  _rpcPipeline;
1054
+ _syncChannelCoordinator = null;
1044
1055
  _delivery;
1045
1056
  _v2E2EE;
1046
1057
  _groupState;
@@ -1152,6 +1163,7 @@ export class AUNClient {
1152
1163
  this._installRiskHooks();
1153
1164
  this._transport.setClassMessageHandler((event, payload) => this._controlMessages().onPush(payload, event.includes('group.')));
1154
1165
  this._transport.setProtocolMetaObserver((meta) => this._observeRpcMeta(meta));
1166
+ this._transport.setSyncControlObserver((meta, method, params) => this._historyChannels().observe(meta, method, params));
1155
1167
  this._transport.setServiceEventVerifier((event, payload) => this._verifyIncomingServiceEvent(event, payload), () => this._identity?.aid ?? '', () => this._serviceEventIdentityVersion);
1156
1168
  this._transport.setProtocolDisconnectCallback((err, closeCode) => this._handleTransportDisconnect(err, closeCode));
1157
1169
  this._transport._onForegroundDrained = () => this._delivery.onForegroundPullsDrained();
@@ -1333,8 +1345,8 @@ export class AUNClient {
1333
1345
  get_ownership_status() {
1334
1346
  return this.getOwnershipStatus();
1335
1347
  }
1336
- async bindOwneraid(ownerAid) { return this._getOwnershipWorkflow().bindOwneraid(ownerAid); }
1337
- async bindSubaid(subAid) { return this._getOwnershipWorkflow().bindSubaid(subAid); }
1348
+ async bindOwneraid(ownerAid, options) { return this._getOwnershipWorkflow().bindOwneraid(ownerAid, options); }
1349
+ async bindSubaid(subAid, options) { return this._getOwnershipWorkflow().bindSubaid(subAid, options); }
1338
1350
  async bindLocalSubaid(subClient) { return this._localOwnershipOperation(subClient); }
1339
1351
  async transferLocalSubaid(subClient, newOwnerClient) { return this._localOwnershipOperation(subClient, newOwnerClient); }
1340
1352
  _createOwnershipOperationClient(slotId) {
@@ -1342,6 +1354,11 @@ export class AUNClient {
1342
1354
  const client = new AUNClient(AID._create({ aid: aid.aid, aunPath: aid.aunPath, certPem: aid.certPem, privateKeyPem: aid.privateKeyPem,
1343
1355
  certValid: aid.isCertValid(), privateKeyValid: aid.isPrivateKeyValid(), deviceId: this._deviceId, slotId,
1344
1356
  verifySsl: aid.verifySsl, rootCaPath: aid.rootCaPath, debug: aid.debug, aidStore: aid._aidStore }));
1357
+ const identity = this._auth.loadIdentityOrNone(), token = String(identity?.access_token ?? ''), expiresAt = identity?.access_token_expires_at;
1358
+ if (identity?.aid === aid.aid && token.startsWith('eyJ') && token.split('.').length === 3
1359
+ && typeof expiresAt === 'number' && expiresAt > Date.now() / 1000 + 30) {
1360
+ Object.assign(client._identity, { access_token: token, access_token_expires_at: expiresAt });
1361
+ }
1345
1362
  client._ownershipOperation = true;
1346
1363
  client._ownershipType = this.getType();
1347
1364
  return client;
@@ -1383,24 +1400,34 @@ export class AUNClient {
1383
1400
  }
1384
1401
  }
1385
1402
  async releaseSubaid(subAid) { return this._getOwnershipWorkflow().releaseSubaid(subAid); }
1386
- async transferSubaid(subAid, newOwnerAid) { return this._getOwnershipWorkflow().transferSubaid(subAid, newOwnerAid); }
1403
+ async transferSubaid(subAid, newOwnerAid, options) { return this._getOwnershipWorkflow().transferSubaid(subAid, newOwnerAid, options); }
1387
1404
  async checkOwnershipConsensus(subAid, force = false) {
1388
1405
  const target = ownershipAid(subAid ?? this._aid, 'sub_aid');
1389
- const record = this._agentMdManager.loadRecord(target);
1406
+ const manager = this._agentMdManager;
1407
+ const record = manager.loadRecord(target);
1390
1408
  const observedEtag = String(record?.remote_etag ?? '');
1409
+ const observation = { root: manager.root, etag: observedEtag, version: Number(record?.observation_version ?? 0), content_hash: typeof record?.content === 'string' ? ownershipSha256(record.content) : '' };
1391
1410
  const cache = this._ownershipConsensusCache ??= new Map();
1392
1411
  const cached = cache.get(target);
1393
1412
  if (!force && cached?.result.status === 'consensus' && record?.remote_status !== 'missing'
1394
- && (observedEtag === cached.observedEtag || observedEtag === cached.result.agent_md_etag)) {
1413
+ && (observedEtag === cached.observedEtag || observedEtag === cached.result.agent_md_etag)
1414
+ && (typeof record?.content !== 'string' || ownershipSha256(record.content) === cached.result.agent_md_sha256)) {
1395
1415
  cached.observedEtag = observedEtag;
1396
1416
  return { ...cached.result };
1397
1417
  }
1418
+ if (!force && !cached) {
1419
+ const local = manager.localOwnershipConsensus(target, record);
1420
+ if (local) {
1421
+ cache.set(target, { observedEtag, result: local });
1422
+ return { ...local };
1423
+ }
1424
+ }
1398
1425
  cache.delete(target);
1399
1426
  const result = { status: 'unavailable', sub_aid: target, owner_aid: null, relation_version: 0, lock: 'unlocked', agent_md_etag: '', agent_md_sha256: '' };
1400
1427
  const entry = { observedEtag, result: { ...result } };
1401
1428
  cache.set(target, entry);
1402
1429
  try {
1403
- const snapshot = await this._agentMdManager.readOwnershipFresh(target);
1430
+ const snapshot = await manager.readOwnershipFresh(target);
1404
1431
  Object.assign(result, { relation_version: snapshot.relation_version, lock: snapshot.lock, agent_md_etag: snapshot.etag,
1405
1432
  agent_md_sha256: snapshot.exists ? ownershipSha256(snapshot.content) : '' });
1406
1433
  if (snapshot.ownership_status)
@@ -1420,8 +1447,13 @@ export class AUNClient {
1420
1447
  result.reason = error instanceof Error ? error.message : String(error);
1421
1448
  result.retryable = result.status === 'unavailable';
1422
1449
  }
1423
- if (cache.get(target) === entry)
1450
+ if (this._agentMdManager === manager && this._ownershipConsensusCache === cache && cache.get(target) === entry) {
1424
1451
  entry.result = { ...result };
1452
+ try {
1453
+ manager.cacheOwnershipSnapshot(target, result, observation);
1454
+ }
1455
+ catch { }
1456
+ }
1425
1457
  return result;
1426
1458
  }
1427
1459
  async _checkOwnershipConsensusFresh(subAid) {
@@ -1437,6 +1469,20 @@ export class AUNClient {
1437
1469
  async bind_owner(ownerAid, options = {}) { return this.bindOwner(ownerAid, options); }
1438
1470
  async releaseOwnership(subjectAid) { throw ownershipFailure('unsupported_protocol', 'legacy releaseOwnership is unsupported; use releaseSubaid'); }
1439
1471
  async release_ownership(subjectAid) { return this.releaseOwnership(subjectAid); }
1472
+ async acceptOwnershipRequests(operationIds) {
1473
+ return this._approveOwnershipRequests(operationIds);
1474
+ }
1475
+ async rejectOwnershipRequests(operationIds, reason) {
1476
+ return this._approveOwnershipRequests(operationIds, true, reason);
1477
+ }
1478
+ async _approveOwnershipRequests(operationIds, reject = false, reason) {
1479
+ const aid = this._aid, generation = this._serviceEventIdentityVersion;
1480
+ return ownershipApprovalBatch(operationIds, async (operationId) => {
1481
+ if (this._aid !== aid || this._serviceEventIdentityVersion !== generation)
1482
+ throw new StateError('ownership approval identity changed', { stringCode: 'conflict' });
1483
+ return reject ? this.rejectOwnershipRequest(operationId, reason) : this.acceptOwnershipRequest(operationId);
1484
+ });
1485
+ }
1440
1486
  async acceptOwnershipRequest(operationId) {
1441
1487
  return this._getOwnershipWorkflow().acceptOwnershipRequest(operationId);
1442
1488
  }
@@ -1655,6 +1701,7 @@ export class AUNClient {
1655
1701
  this._installRiskHooks();
1656
1702
  this._transport.setClassMessageHandler((event, payload) => this._controlMessages().onPush(payload, event.includes('group.')));
1657
1703
  this._transport.setProtocolMetaObserver((meta) => this._observeRpcMeta(meta));
1704
+ this._transport.setSyncControlObserver((meta, method, params) => this._historyChannels().observe(meta, method, params));
1658
1705
  this._transport.setServiceEventVerifier((event, payload) => this._verifyIncomingServiceEvent(event, payload), () => this._identity?.aid ?? '', () => this._serviceEventIdentityVersion);
1659
1706
  this._transport.setProtocolDisconnectCallback((err, closeCode) => this._handleTransportDisconnect(err, closeCode));
1660
1707
  this._transport._onForegroundDrained = () => this._delivery.onForegroundPullsDrained();
@@ -1710,6 +1757,56 @@ export class AUNClient {
1710
1757
  return this._peerDirectory.peers();
1711
1758
  }
1712
1759
  /** transport 的 meta observer:吸收 gateway 注入的 _meta 字段。失败不影响业务。 */
1760
+ _historyChannels() {
1761
+ return this._syncChannelCoordinator ??= new SyncChannels({
1762
+ main: () => this._transport,
1763
+ current: () => this._state === 'ready' && !this._closing && this._transport.isConnected(),
1764
+ wake: () => this._delivery?.requestBackgroundPullRecovery(),
1765
+ owner: () => String(this._aid ?? ''),
1766
+ namespace: (method, params) => this._rpcPipeline.pullGateKeyForCall(method, params).split('|')[0],
1767
+ pendingNamespaces: () => [...this._delivery.pendingHistoryNamespaces(), ...this._rpcPipeline.pendingHistoryNamespaces()],
1768
+ fail: (method, params, error) => this._dispatcher.enqueue('sync.error', { namespace: params.sender_aid ? this._delivery.peerNamespace(String(params.sender_aid)) : `group:${String(params.group_id ?? params.group_aid ?? '')}`, method, code: 'OVERSIZED_MESSAGE', error: error instanceof Error ? error.message : String(error) }),
1769
+ create: async (parent, timeout = 35000, signal) => {
1770
+ const deadline = Date.now() + timeout;
1771
+ const dispatcher = new EventDispatcher(this._logger.for('aun_core.events'));
1772
+ const transport = new RPCTransport({ eventDispatcher: dispatcher, rpcBudget: this._transport.rpcBudget, syncAuxiliary: true,
1773
+ timeout, verifySsl: this._configModel.verifySsl, logger: this._logger.for('aun_core.transport') });
1774
+ transport.setSyncControlObserver((meta, method, params) => this._historyChannels().observe(meta, method, params));
1775
+ transport.setRequestAdmission(this._transport._requestAdmission);
1776
+ transport.setRequestCheck(this._transport._requestCheck);
1777
+ transport.setProtocolDisconnectCallback(() => this._historyChannels().auxiliaryDisconnected(transport));
1778
+ const abort = () => { void transport.close(); };
1779
+ signal?.addEventListener('abort', abort, { once: true });
1780
+ try {
1781
+ if (signal?.aborted)
1782
+ throw new TimeoutError('history sync cancelled', { retryable: true });
1783
+ const challenge = await transport.connect(this._gatewayUrl);
1784
+ if (Date.now() >= deadline || signal?.aborted)
1785
+ throw new TimeoutError('history sync deadline exceeded', { retryable: true });
1786
+ transport.setTimeout(Math.max(1, deadline - Date.now()));
1787
+ const token = AuthFlow._getCachedAccessToken(this._identity ?? {})
1788
+ || AuthFlow._getCachedAccessToken(this._sessionParams ?? {});
1789
+ if (!token)
1790
+ throw new ConnectionError('auxiliary sync connection has no valid access token');
1791
+ const hello = await this._auth.initializeWithToken(transport, challenge, token, { deviceId: this._deviceId,
1792
+ slotId: this._slotId, connectionKind: 'short', shortTtlMs: 0, extraInfo: { _sync_parent: parent } });
1793
+ if (!isJsonObject(hello.connection) || !hello.connection.id)
1794
+ throw new ConnectionError('auxiliary sync connection has no identity');
1795
+ if (!isJsonObject(hello.negotiated_capabilities) || hello.negotiated_capabilities.elastic_connections_v1 !== true || hello.negotiated_capabilities.sync_channels_v1 !== true)
1796
+ throw new ConnectionError('auxiliary sync capabilities were not negotiated');
1797
+ return { id: String(hello.connection.id), transport, dispose: () => dispatcher.close() };
1798
+ }
1799
+ catch (error) {
1800
+ await transport.close();
1801
+ await dispatcher.close();
1802
+ throw error;
1803
+ }
1804
+ finally {
1805
+ signal?.removeEventListener('abort', abort);
1806
+ }
1807
+ },
1808
+ });
1809
+ }
1713
1810
  _observeRpcMeta(meta) {
1714
1811
  this._agentMdManager.observeRpcMeta(meta, this._aid);
1715
1812
  this._groupIndexMetaCache.observeRpcMeta(meta, { localAid: this._aid ?? '' });
@@ -2028,6 +2125,9 @@ export class AUNClient {
2028
2125
  if (!pending?.private_key_pem || !pending.public_key_der_b64)
2029
2126
  return false;
2030
2127
  }
2128
+ const local = this._agentMdManager.localOwnershipConsensus(target, this._agentMdManager.loadRecord(target));
2129
+ if (local?.owner_aid === this._aid)
2130
+ return true;
2031
2131
  const result = await this._entityLifecycle(target, type);
2032
2132
  const data = result;
2033
2133
  const entity = (isJsonObject(data.group) ? data.group : isJsonObject(data.organization) ? data.organization : data);
@@ -2201,12 +2301,19 @@ export class AUNClient {
2201
2301
  if (!aid)
2202
2302
  return;
2203
2303
  try {
2204
- const checked = await this._agentMdManager.check(aid, 0);
2205
- if (!checked.remote_found) {
2206
- await this._ensureInitialAgentMd();
2207
- }
2208
- else if (checked.in_sync === false) {
2209
- await this._agentMdManager.download(aid);
2304
+ const record = this._agentMdManager.loadRecord(aid);
2305
+ const verified = record?.verified_agent_md;
2306
+ const local = record?.content && record.remote_status !== 'missing' && record.remote_etag
2307
+ && (record.local_etag === record.remote_etag || record.verify_status === 'verified' && verified?.etag === record.remote_etag && verified.content_hash === record.local_etag
2308
+ || this._agentMdManager.localOwnershipConsensus(aid, record));
2309
+ if (!local) {
2310
+ const checked = await this._agentMdManager.check(aid, 0);
2311
+ if (!checked.remote_found) {
2312
+ await this._ensureInitialAgentMd();
2313
+ }
2314
+ else if (checked.in_sync === false) {
2315
+ await this._agentMdManager.download(aid);
2316
+ }
2210
2317
  }
2211
2318
  }
2212
2319
  catch (exc) {
@@ -4512,6 +4619,7 @@ export class AUNClient {
4512
4619
  // ── 内部:连接 ────────────────────────────────────────────
4513
4620
  /** 执行一次连接流程 */
4514
4621
  async _connectOnce(params, allowReauth, reconnectOwner, connectionOwner) {
4622
+ this._syncChannelCoordinator?.reset();
4515
4623
  await this._restoreRiskState();
4516
4624
  this._assertRiskReconnect();
4517
4625
  this._riskNegotiated = false;
@@ -4623,6 +4731,7 @@ export class AUNClient {
4623
4731
  this._migrationPending = false;
4624
4732
  this._lastDisconnectInfo = null;
4625
4733
  this._state = 'ready';
4734
+ this._historyChannels().bind(this._gatewayConnectionId, this._negotiatedCapabilities.elastic_connections_v1 === true && this._negotiatedCapabilities.sync_channels_v1 === true && params.connection_kind !== 'short');
4626
4735
  this._connectedAt = Date.now();
4627
4736
  if (Array.isArray(params.gateways)) {
4628
4737
  this._gatewayCandidates = [...new Set(params.gateways
@@ -5615,6 +5724,7 @@ export class AUNClient {
5615
5724
  }
5616
5725
  /** 停止所有后台任务 */
5617
5726
  _stopBackgroundTasks() {
5727
+ this._syncChannelCoordinator?.reset();
5618
5728
  this._stopCredentialRenewal();
5619
5729
  this._auth.invalidateStrictPkiCache();
5620
5730
  this._certCache.clear();