@agentunion/fastaun 0.5.27 → 0.5.29

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 (77) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/_packed_docs/CHANGELOG.md +55 -0
  3. package/_packed_docs/INDEX.md +23 -3
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +15 -11
  5. package/_packed_docs/sdk/0.5.28-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +228 -0
  6. package/_packed_docs/sdk/0.5.28-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +146 -0
  7. package/_packed_docs/sdk/0.5.29-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +180 -0
  8. package/_packed_docs/sdk/0.5.29-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +164 -0
  9. package/_packed_docs/sdk/09-/347/273/204/347/273/207/346/234/215/345/212/241RPC/346/211/213/345/206/214.md +90 -90
  10. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +6 -4
  11. package/_packed_docs/sdk/INDEX.md +14 -4
  12. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +1 -1
  13. package/_packed_docs/sdk//345/207/255/350/257/201/344/270/216/347/273/204/347/273/207/346/234/215/345/212/241SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +1 -1
  14. package/_packed_docs//346/216/247/345/210/266/346/266/210/346/201/257/344/270/216/350/256/276/345/244/207/350/203/275/345/212/233/345/215/217/345/225/206/346/226/271/346/241/210.md +426 -0
  15. package/_packed_docs//346/266/210/346/201/257/345/220/214/346/255/245/344/270/216/345/216/206/345/217/262/346/213/211/345/217/226/344/273/243/347/240/201/345/256/241/346/237/245/351/227/256/351/242/230/346/270/205/345/215/225.md +279 -229
  16. package/_packed_docs//351/243/216/346/216/247/345/223/215/345/272/224/344/270/216SDK/345/215/217/345/220/214/346/226/271/346/241/210.md +381 -0
  17. package/dist/agent-md-changes.d.ts +30 -0
  18. package/dist/agent-md-changes.js +168 -0
  19. package/dist/agent-md-changes.js.map +1 -0
  20. package/dist/agent-md-schema.d.ts +1 -0
  21. package/dist/agent-md-schema.js +29 -12
  22. package/dist/agent-md-schema.js.map +1 -1
  23. package/dist/agent-md.d.ts +9 -0
  24. package/dist/agent-md.js +107 -36
  25. package/dist/agent-md.js.map +1 -1
  26. package/dist/aid-store.d.ts +14 -1
  27. package/dist/aid-store.js +163 -61
  28. package/dist/aid-store.js.map +1 -1
  29. package/dist/auth.d.ts +10 -0
  30. package/dist/auth.js +44 -4
  31. package/dist/auth.js.map +1 -1
  32. package/dist/client/control-messages.d.ts +31 -0
  33. package/dist/client/control-messages.js +496 -0
  34. package/dist/client/control-messages.js.map +1 -0
  35. package/dist/client/delivery.js +12 -3
  36. package/dist/client/delivery.js.map +1 -1
  37. package/dist/client/group-state.js +2 -3
  38. package/dist/client/group-state.js.map +1 -1
  39. package/dist/client/lifecycle.js +8 -0
  40. package/dist/client/lifecycle.js.map +1 -1
  41. package/dist/client/rpc-pipeline.js +76 -13
  42. package/dist/client/rpc-pipeline.js.map +1 -1
  43. package/dist/client/v2-e2ee.d.ts +3 -0
  44. package/dist/client/v2-e2ee.js +13 -4
  45. package/dist/client/v2-e2ee.js.map +1 -1
  46. package/dist/client.d.ts +27 -1
  47. package/dist/client.js +348 -38
  48. package/dist/client.js.map +1 -1
  49. package/dist/discovery.d.ts +3 -0
  50. package/dist/discovery.js +53 -2
  51. package/dist/discovery.js.map +1 -1
  52. package/dist/events.js +14 -1
  53. package/dist/events.js.map +1 -1
  54. package/dist/ownership-v21.d.ts +2 -1
  55. package/dist/ownership-v21.js +17 -3
  56. package/dist/ownership-v21.js.map +1 -1
  57. package/dist/ownership-workflow.js +9 -5
  58. package/dist/ownership-workflow.js.map +1 -1
  59. package/dist/risk-control.d.ts +68 -0
  60. package/dist/risk-control.js +344 -0
  61. package/dist/risk-control.js.map +1 -0
  62. package/dist/semantic-facade.js +4 -2
  63. package/dist/semantic-facade.js.map +1 -1
  64. package/dist/semantic-protocol.js +2 -0
  65. package/dist/semantic-protocol.js.map +1 -1
  66. package/dist/storage/lowlevel.d.ts +1 -0
  67. package/dist/storage/lowlevel.js +2 -2
  68. package/dist/storage/lowlevel.js.map +1 -1
  69. package/dist/tools/cross-sdk-agent.d.ts +1 -1
  70. package/dist/tools/cross-sdk-agent.js +16 -34
  71. package/dist/tools/cross-sdk-agent.js.map +1 -1
  72. package/dist/transport.d.ts +21 -1
  73. package/dist/transport.js +199 -20
  74. package/dist/transport.js.map +1 -1
  75. package/dist/version.d.ts +1 -1
  76. package/dist/version.js +1 -1
  77. package/package.json +8 -8
package/dist/aid-store.js CHANGED
@@ -9,6 +9,7 @@ import { join } from 'node:path';
9
9
  import { homedir } from 'node:os';
10
10
  import { readFileSync, writeFileSync } from 'node:fs';
11
11
  import { AID } from './aid.js';
12
+ import { RiskController } from './risk-control.js';
12
13
  import * as codes from './error-codes.js';
13
14
  import { certCommonName, certMatchesFingerprint, certTimeError, parseAgentMdTailSignature, publicKeyMatchesFingerprint, signBytes, signDocument, verifyDocument, verifySignatureWithCert } from './cert-utils.js';
14
15
  import { certFingerprint as _certFingerprint } from './cert-utils.js';
@@ -20,11 +21,12 @@ import { GatewayDiscovery } from './discovery.js';
20
21
  import { DnsResilientNet } from './net.js';
21
22
  import { AUNLogger } from './logger.js';
22
23
  import { getDeviceId, normalizeSlotId } from './config.js';
23
- import { AUNError, ClientSignatureError, IdentityConflictError, NotFoundError, ValidationError } from './errors.js';
24
+ import { AUNError, ClientSignatureError, IdentityConflictError, NotFoundError, StateError, ValidationError } from './errors.js';
24
25
  import { AgentMdManager, buildDefaultAgentMd } from './agent-md.js';
25
26
  import { parseFileFrontmatter, validateAgentMdCertificate, validateAgentMdDocument, validateAgentMdReadDocument } from './agent-md-schema.js';
26
27
  import { LocalTokenStore } from './keystore/local-token-store.js';
27
28
  import { AuthFlow } from './auth.js';
29
+ import { isJsonObject } from './types.js';
28
30
  import { ownershipFailure } from './ownership-v21.js';
29
31
  import { validateAIDFormat } from './validators.js';
30
32
  function resultError(r) {
@@ -98,6 +100,66 @@ export class AIDStore {
98
100
  _agentMdManager;
99
101
  _ownershipInflight = new WeakMap();
100
102
  _peerAuth;
103
+ _riskControllers = new Map();
104
+ _liveRiskControllers = new Map();
105
+ _riskLoads = new Map();
106
+ _riskPersistedStates = new Map();
107
+ _ownedRiskControllers = new Set();
108
+ setRiskController(aid, controller) { this._liveRiskControllers.set(aid, controller); }
109
+ async _riskForAid(aid) {
110
+ const live = await this._liveRiskControllers.get(aid)?.();
111
+ if (live)
112
+ return live;
113
+ const existing = this._riskControllers.get(aid);
114
+ const stored = this._tokenStore._loadMetadataStrict(aid)?.[`risk_state_v1:${this.deviceId}`];
115
+ const raw = stored ? (typeof stored === 'string' ? stored : JSON.stringify(stored)) : '';
116
+ if (existing && this._riskPersistedStates.get(aid) === raw)
117
+ return existing;
118
+ const loading = this._riskLoads.get(aid);
119
+ if (loading)
120
+ return await loading;
121
+ const task = this._loadRiskForAid(aid, raw);
122
+ this._riskLoads.set(aid, task);
123
+ try {
124
+ return await task;
125
+ }
126
+ finally {
127
+ if (this._riskLoads.get(aid) === task)
128
+ this._riskLoads.delete(aid);
129
+ }
130
+ }
131
+ async _loadRiskForAid(aid, raw) {
132
+ const controller = new RiskController({ persist: async (state) => {
133
+ const saved = JSON.stringify(state);
134
+ this._tokenStore.saveMetadata(aid, { ...(this._tokenStore._loadMetadataStrict(aid) ?? {}), [`risk_state_v1:${this.deviceId}`]: state });
135
+ this._riskPersistedStates.set(aid, saved);
136
+ } });
137
+ this._riskPersistedStates.set(aid, raw);
138
+ if (raw) {
139
+ const state = JSON.parse(raw);
140
+ if (!isJsonObject(state))
141
+ throw new StateError('persisted risk state is unavailable', { stringCode: 'risk_state_unavailable' });
142
+ await controller.restorePinned(state, { aid, device_id: this.deviceId, slot_id: this.slotId, connection_id: '' });
143
+ }
144
+ const previous = this._riskControllers.get(aid);
145
+ if (previous && this._ownedRiskControllers.has(previous)) {
146
+ previous.close();
147
+ this._ownedRiskControllers.delete(previous);
148
+ }
149
+ this._riskControllers.set(aid, controller);
150
+ this._ownedRiskControllers.add(controller);
151
+ return controller;
152
+ }
153
+ async _riskFetchForAid(aid, url, init, perform, scope) {
154
+ const controller = await this._riskForAid(aid);
155
+ const release = controller.acquire(scope);
156
+ try {
157
+ return await perform(url, init);
158
+ }
159
+ finally {
160
+ release();
161
+ }
162
+ }
101
163
  async sign(aid, input, options = {}) {
102
164
  try {
103
165
  if (!['text', 'file'].includes(options.inputType ?? 'text') || !['raw', 'document'].includes(options.format ?? 'raw'))
@@ -262,32 +324,41 @@ export class AIDStore {
262
324
  });
263
325
  }
264
326
  close() {
327
+ for (const controller of this._ownedRiskControllers)
328
+ controller.close();
329
+ this._ownedRiskControllers.clear();
265
330
  this._keystore.close();
266
331
  this._tokenStore.close();
267
332
  const net = this._net;
268
333
  if (typeof net.close === 'function')
269
334
  net.close();
270
335
  }
271
- async _resolveAgentMdPeerCertificate(target, certFingerprint, signedAt) {
336
+ _riskPeerAuth(actorAid) {
337
+ const auth = new AuthFlow({ tokenStore: this._tokenStore, crypto: this._crypto, deviceId: this.deviceId, slotId: this.slotId, verifySsl: this._verifySsl, rootCaPath: this._rootCaPath, logger: this._log.for('aun_core.auth'), net: this._net });
338
+ auth.setHttpHandler((url, init, perform) => this._riskFetchForAid(actorAid, url, init, perform, 'http:gateway:pki'));
339
+ return auth;
340
+ }
341
+ async _resolveAgentMdPeerCertificate(target, certFingerprint, signedAt, actorAid) {
342
+ const auth = actorAid ? this._riskPeerAuth(actorAid) : this._peerAuth;
272
343
  const fp = String(certFingerprint ?? '').trim().toLowerCase();
273
344
  const cachedCert = this._keystore.loadCert(target, fp || undefined);
274
345
  if (cachedCert && (!fp || certMatchesFingerprint(cachedCert, fp) || publicKeyMatchesFingerprint(cachedCert, fp))) {
275
346
  if (signedAt !== undefined)
276
- await this._verifyDownloadedPeerCertificate(await this._resolveGateway(target), target, cachedCert, fp, signedAt);
347
+ await this._verifyDownloadedPeerCertificate(await this._resolveGateway(target, actorAid), target, cachedCert, fp, signedAt, auth);
277
348
  return AID._create({ aid: target, aunPath: this.aunPath, certPem: cachedCert, privateKeyPem: null, certValid: true, privateKeyValid: false, deviceId: this.deviceId, slotId: this.slotId, verifySsl: this._verifySsl, rootCaPath: this._rootCaPath, debug: this._debug });
278
349
  }
279
350
  if (fp) {
280
- const gatewayUrl = await this._resolveGateway(target);
281
- const certPem = await this._net.httpGetText(pkiCertUrl(gatewayUrl, target, fp), 10_000);
282
- await this._verifyDownloadedPeerCertificate(gatewayUrl, target, certPem, fp, signedAt);
351
+ const gatewayUrl = await this._resolveGateway(target, actorAid);
352
+ const certPem = actorAid ? await auth._fetchRiskText(pkiCertUrl(gatewayUrl, target, fp)) : await this._net.httpGetText(pkiCertUrl(gatewayUrl, target, fp), 10_000);
353
+ await this._verifyDownloadedPeerCertificate(gatewayUrl, target, certPem, fp, signedAt, auth);
283
354
  this._keystore.saveCert(target, certPem, _certFingerprint(certPem), { makeActive: false });
284
355
  return AID._create({ aid: target, aunPath: this.aunPath, certPem, privateKeyPem: null, certValid: true, privateKeyValid: false });
285
356
  }
286
- const gatewayUrl = await this._resolveGateway(target);
287
- const certPem = await this._registerFlow.fetchPeerCert(gatewayUrl, target);
357
+ const gatewayUrl = await this._resolveGateway(target, actorAid);
358
+ const certPem = actorAid ? await auth._fetchRiskText(pkiCertUrl(gatewayUrl, target)) : await this._registerFlow.fetchPeerCert(gatewayUrl, target);
288
359
  if (!certPem)
289
360
  throw new Error(`certificate not found for aid: ${target}`);
290
- await this._verifyDownloadedPeerCertificate(gatewayUrl, target, certPem, undefined, signedAt);
361
+ await this._verifyDownloadedPeerCertificate(gatewayUrl, target, certPem, undefined, signedAt, auth);
291
362
  this._keystore.saveCert(target, certPem);
292
363
  return AID._create({ aid: target, aunPath: this.aunPath, certPem, privateKeyPem: null, certValid: true, privateKeyValid: false });
293
364
  }
@@ -412,6 +483,11 @@ export class AIDStore {
412
483
  }
413
484
  // ── 联网方法 ──────────────────────────────────────────────────
414
485
  async register(aid, options) {
486
+ if (['group', 'org'].includes(String(options?.type ?? '').trim()))
487
+ return resultErr(codes.INVALID_AID_FORMAT, 'group/org must use their dedicated creation flow');
488
+ return this._registerIdentity(aid, options);
489
+ }
490
+ async _registerIdentity(aid, options) {
415
491
  const target = String(aid ?? '').trim();
416
492
  this._log.for('aun_core.aid_store').debug(`register enter: aid=${target || '-'}`);
417
493
  try {
@@ -420,8 +496,8 @@ export class AIDStore {
420
496
  const entity = ['group', 'org'].includes(type);
421
497
  if (entity && !owner)
422
498
  throw new ValidationError('group/org registration requires owner');
423
- if (!type || type === 'human' && owner)
424
- throw new ValidationError('register requires type; human forbids owner');
499
+ if (!type || type === 'human' && owner || type !== 'human' && !owner)
500
+ throw new ValidationError('register requires type; human forbids owner; other types require owner');
425
501
  if (owner)
426
502
  validateAIDFormat(owner, 'owner');
427
503
  const exttype = String(options?.exttype ?? '').trim();
@@ -437,9 +513,11 @@ export class AIDStore {
437
513
  curve: result.curve,
438
514
  });
439
515
  if (!entity) {
440
- const initialized = await this._createInitialRegistrationAgentMd(target, type, exttype);
441
- if (!initialized.ok)
442
- return initialized;
516
+ if (type === 'human') {
517
+ const initialized = await this._createInitialRegistrationAgentMd(target, type, exttype);
518
+ if (!initialized.ok)
519
+ return initialized;
520
+ }
443
521
  if (owner) {
444
522
  await this._bindRegistrationOwner(target, owner);
445
523
  }
@@ -469,6 +547,7 @@ export class AIDStore {
469
547
  const client = new AUNClient(AID._create({ aid: target, aunPath: this.aunPath, certPem: identity.certPem, privateKeyPem: identity.privateKeyPem,
470
548
  certValid: identity.isCertValid(), privateKeyValid: identity.isPrivateKeyValid(), deviceId: this.deviceId, slotId: `ownership-${randomUUID()}`,
471
549
  verifySsl: this._verifySsl, rootCaPath: this._rootCaPath, debug: this._debug, aidStore: this }));
550
+ client._ownershipOperation = true;
472
551
  try {
473
552
  await client.connect({ connection_kind: 'short', background_sync: false, auto_reconnect: false });
474
553
  const result = await client.bindOwneraid(owner);
@@ -588,48 +667,44 @@ export class AIDStore {
588
667
  const record = this._agentMdManager.loadRecord(target);
589
668
  if (data.agent_md?.etag !== undefined && data.agent_md.etag !== String(record?.remote_etag ?? ''))
590
669
  throw new Error('displayed agent.md ETag does not match the current observation');
591
- const cached = record?.ownership_snapshot;
592
670
  const content = data.agent_md?.content ?? record?.content;
593
671
  const hash = typeof content === 'string' ? AgentMdManager.contentEtag(content).slice(1, -1) : '';
594
672
  const bypass = opts.ownershipTtlMs !== undefined && opts.ownershipTtlMs <= 0;
595
- if (!bypass && record?.remote_etag && cached?.agent_md_etag === record.remote_etag && cached.sub_aid === target && cached.status !== 'unavailable' && hash && cached.agent_md_sha256 === hash) {
596
- data.ownership = { ...JSON.parse(JSON.stringify(cached)), cached: true };
673
+ const observedHash = typeof record?.content === 'string' ? AgentMdManager.contentEtag(record.content).slice(1, -1) : '';
674
+ const observation = { root: this._agentMdManager.root, etag: String(record?.remote_etag ?? ''), version: Number(record?.observation_version ?? 0), content_hash: observedHash };
675
+ const key = JSON.stringify([target, observation, hash]);
676
+ let flights = this._ownershipInflight.get(opts.ownership);
677
+ if (!flights)
678
+ this._ownershipInflight.set(opts.ownership, flights = new Map());
679
+ let pending = bypass ? undefined : flights.get(key);
680
+ if (!pending) {
681
+ pending = (async () => {
682
+ const checker = opts.ownership;
683
+ const checked = bypass && typeof checker._checkOwnershipConsensusFresh === 'function'
684
+ ? await checker._checkOwnershipConsensusFresh.call(opts.ownership, target)
685
+ : await opts.ownership.checkOwnershipConsensus(target);
686
+ if (['consensus', 'single_sided', 'released', 'unbound'].includes(checked.status) && (checked.sub_aid !== target || checked.agent_md_etag !== observation.etag || checked.agent_md_sha256 !== hash || observedHash !== hash))
687
+ throw new Error('ownership snapshot does not match the observed agent.md');
688
+ const snapshot = { ...JSON.parse(JSON.stringify(checked)), checked_at: Date.now(), cached: false };
689
+ delete snapshot.owner_md;
690
+ delete snapshot.owner_md_sha256;
691
+ if (!this._agentMdManager.cacheOwnershipSnapshot(target, snapshot, observation))
692
+ throw new Error('agent.md observation changed during ownership check');
693
+ return snapshot;
694
+ })();
695
+ if (!bypass)
696
+ flights.set(key, pending);
597
697
  }
598
- else {
599
- const observedHash = typeof record?.content === 'string' ? AgentMdManager.contentEtag(record.content).slice(1, -1) : '';
600
- const observation = { root: this._agentMdManager.root, etag: String(record?.remote_etag ?? ''), version: Number(record?.observation_version ?? 0), content_hash: observedHash };
601
- const key = JSON.stringify([target, observation, hash]);
602
- let flights = this._ownershipInflight.get(opts.ownership);
603
- if (!flights)
604
- this._ownershipInflight.set(opts.ownership, flights = new Map());
605
- let pending = bypass ? undefined : flights.get(key);
606
- if (!pending) {
607
- pending = (async () => {
608
- const checker = opts.ownership;
609
- const checked = bypass && typeof checker._checkOwnershipConsensusFresh === 'function'
610
- ? await checker._checkOwnershipConsensusFresh.call(opts.ownership, target)
611
- : await opts.ownership.checkOwnershipConsensus(target);
612
- if (['consensus', 'single_sided', 'released', 'unbound'].includes(checked.status) && (checked.sub_aid !== target || checked.agent_md_etag !== observation.etag || checked.agent_md_sha256 !== hash || observedHash !== hash))
613
- throw new Error('ownership snapshot does not match the observed agent.md');
614
- const snapshot = { ...JSON.parse(JSON.stringify(checked)), checked_at: Date.now(), cached: false };
615
- if (!this._agentMdManager.cacheOwnershipSnapshot(target, snapshot, observation))
616
- throw new Error('agent.md observation changed during ownership check');
617
- return snapshot;
618
- })();
619
- if (!bypass)
620
- flights.set(key, pending);
621
- }
622
- try {
623
- data.ownership = JSON.parse(JSON.stringify(await pending));
624
- }
625
- finally {
626
- if (flights.get(key) === pending)
627
- flights.delete(key);
628
- }
698
+ try {
699
+ data.ownership = JSON.parse(JSON.stringify(await pending));
700
+ }
701
+ finally {
702
+ if (flights.get(key) === pending)
703
+ flights.delete(key);
629
704
  }
630
705
  }
631
706
  catch (error) {
632
- data.ownership = { status: 'unavailable', sub_aid: target, owner_aid: null, relation_version: 0, lock: 'unlocked', agent_md_etag: '', agent_md_sha256: '', owner_md_sha256: '', code: 'unavailable', reason: error instanceof Error ? error.message : String(error), retryable: true, checked_at: Date.now(), cached: false };
707
+ data.ownership = { status: 'unavailable', sub_aid: target, owner_aid: null, relation_version: 0, lock: 'unlocked', agent_md_etag: '', agent_md_sha256: '', code: 'unavailable', reason: error instanceof Error ? error.message : String(error), retryable: true, checked_at: Date.now(), cached: false };
633
708
  }
634
709
  return resultOk(data);
635
710
  }
@@ -649,16 +724,16 @@ export class AIDStore {
649
724
  return agentMdFailure(exc);
650
725
  }
651
726
  }
652
- async _verifyDownloadedPeerCertificate(gatewayUrl, aid, certPem, certFingerprint = '', signedAt) {
727
+ async _verifyDownloadedPeerCertificate(gatewayUrl, aid, certPem, certFingerprint = '', signedAt, auth = this._peerAuth) {
653
728
  const expectedFp = String(certFingerprint ?? '').trim().toLowerCase();
654
729
  if (expectedFp && !certMatchesFingerprint(certPem, expectedFp) && !(signedAt !== undefined && publicKeyMatchesFingerprint(certPem, expectedFp))) {
655
730
  throw new ValidationError(`certificate fingerprint mismatch for aid: ${aid}`);
656
731
  }
657
732
  if (signedAt === undefined)
658
- await this._peerAuth.verifyPeerCertificate(gatewayUrl, certPem, aid);
733
+ await auth.verifyPeerCertificate(gatewayUrl, certPem, aid);
659
734
  else {
660
735
  validateAgentMdCertificate(certPem, aid, signedAt, { requireCurrentValidity: false, readCompatibility: true });
661
- await this._peerAuth._verifyAuthCertChain(gatewayUrl, new X509Certificate(certPem), aid, signedAt);
736
+ await auth._verifyAuthCertChain(gatewayUrl, new X509Certificate(certPem), aid, signedAt);
662
737
  }
663
738
  }
664
739
  _authIdentityFromAid(aid) {
@@ -670,6 +745,7 @@ export class AIDStore {
670
745
  };
671
746
  }
672
747
  async _uploadAgentMdToken(aid, gatewayUrl) {
748
+ const risk = await this._riskForAid(aid.aid);
673
749
  const auth = new AuthFlow({
674
750
  tokenStore: this._tokenStore,
675
751
  crypto: this._crypto,
@@ -681,6 +757,8 @@ export class AIDStore {
681
757
  logger: this._log.for('aun_core.auth'),
682
758
  net: this._net,
683
759
  });
760
+ auth.setRequestAdmission((request) => risk.acquire(request));
761
+ auth.setHttpHandler((url, init, perform) => this._riskFetchForAid(aid.aid, url, init, perform, 'http:gateway:pki'));
684
762
  auth.setIdentity(this._authIdentityFromAid(aid));
685
763
  const result = await auth.authenticate(gatewayUrl, { aid: aid.aid });
686
764
  const token = String(result.access_token ?? result.token ?? result.kite_token ?? '').trim();
@@ -689,6 +767,9 @@ export class AIDStore {
689
767
  return token;
690
768
  }
691
769
  async uploadAgentMd(aid, content, options = {}) {
770
+ return this._uploadAgentMd(aid, content, options);
771
+ }
772
+ async _uploadAgentMd(aid, content, options, onCommitted) {
692
773
  const target = String(aid ?? '').trim();
693
774
  try {
694
775
  this._registerFlow.validateAidName(target);
@@ -700,7 +781,7 @@ export class AIDStore {
700
781
  const current = loaded.data.aid;
701
782
  const pending = content === undefined || content === null ? this._agentMdManager.pendingUpload(target) : null;
702
783
  const raw = pending?.content ?? content ?? (String((this._agentMdManager._loadRecord?.(target, true) ?? this._agentMdManager.loadRecord(target))?.local_draft_content ?? '') || this._agentMdManager.readContent(target));
703
- const parsed = validateAgentMdDocument(raw, { expectedAid: target, validateOwnership: false });
784
+ const parsed = validateAgentMdDocument(raw, { expectedAid: target, validateOwnership: false, forUpload: true });
704
785
  const meta = parsed.frontmatter;
705
786
  const entity = ['group', 'org'].includes(String(meta.type));
706
787
  const uploaderTarget = String(options.uploaderAid ?? options.uploader_aid ?? (entity ? meta.owner : target)).trim();
@@ -727,22 +808,40 @@ export class AIDStore {
727
808
  uploadViaGatewayHost: true,
728
809
  ownerAidGetter: () => entity ? uploaderTarget : target,
729
810
  currentAidGetter: () => entity ? uploader : current,
811
+ onCommitted: onCommitted ? (value, notice) => onCommitted(value, notice, manager) : (async (value, notice) => {
812
+ const { AUNClient } = await import('./client.js');
813
+ const client = new AUNClient(AID._create({ aid: uploader.aid, aunPath: this.aunPath, certPem: uploader.certPem, privateKeyPem: uploader.privateKeyPem,
814
+ certValid: uploader.isCertValid(), privateKeyValid: uploader.isPrivateKeyValid(), deviceId: this.deviceId, slotId: `agent-md-${randomUUID()}`,
815
+ verifySsl: this._verifySsl, rootCaPath: this._rootCaPath, debug: this._debug, aidStore: this }));
816
+ client._ownershipOperation = true;
817
+ try {
818
+ await client.connect({ connection_kind: 'short', background_sync: false, auto_reconnect: false });
819
+ await client._getAgentMdChanges().committed(value, notice, manager);
820
+ }
821
+ finally {
822
+ await client.close();
823
+ }
824
+ }),
730
825
  entityIdentityGetter: options.entityIdentityGetter ?? (async (value, type) => {
731
- const gateway = await this._resolveGateway(value);
732
- const material = await this._peerAuth.resolveCurrentEntityCertificate(gateway, value, type ?? 'org');
826
+ const gateway = await this._resolveGateway(value, uploaderTarget);
827
+ const material = await this._riskPeerAuth(uploaderTarget).resolveCurrentEntityCertificate(gateway, value, type ?? 'org');
733
828
  const certPem = material.cert_pem;
734
829
  return AID._create({ aid: value, aunPath: this.aunPath, certPem, certValid: true, privateKeyPem: null, privateKeyValid: false });
735
830
  }),
736
831
  entitySignerResolver: async (value, fingerprint) => {
737
- const material = await this._peerAuth.resolveOwnershipCertificate(await this._resolveGateway(value), value, fingerprint, 'signing');
832
+ const material = await this._riskPeerAuth(uploaderTarget).resolveOwnershipCertificate(await this._resolveGateway(value, uploaderTarget), value, fingerprint, 'signing');
738
833
  return AID._create({ aid: value, aunPath: this.aunPath, certPem: material.cert_pem, certValid: true, privateKeyPem: null, privateKeyValid: false });
739
834
  },
740
835
  entityOwnerResolver: options.entityOwnerResolver,
741
- peerResolver: (value, fingerprint, signedAt) => this._resolveAgentMdPeerCertificate(value, fingerprint, signedAt),
742
- gatewayResolver: (value) => this._resolveGateway(value),
743
- accessTokenResolver: async () => this._uploadAgentMdToken(uploader, await this._resolveGateway(uploaderTarget)),
836
+ peerResolver: (value, fingerprint, signedAt) => this._resolveAgentMdPeerCertificate(value, fingerprint, signedAt, uploaderTarget),
837
+ gatewayResolver: (value) => this._resolveGateway(value, uploaderTarget),
838
+ accessTokenResolver: async () => this._uploadAgentMdToken(uploader, await this._resolveGateway(uploaderTarget, uploaderTarget)),
744
839
  aidValidator: (value) => this._registerFlow.validateAidName(value),
745
840
  });
841
+ manager.setHttpHandler((url, init, perform) => {
842
+ const headers = new Headers(init.headers);
843
+ return this._riskFetchForAid(uploaderTarget, url, init, perform, headers.has('X-AUN-Ownership-Check') || headers.has('X-AUN-Ownership-Stage') ? 'http:nameservice:ownership' : 'http:nameservice:agent_md');
844
+ });
746
845
  if (pending) {
747
846
  await manager.resumePendingUpload(target, current);
748
847
  const record = manager.loadRecord(target);
@@ -1011,7 +1110,7 @@ export class AIDStore {
1011
1110
  return Promise.resolve(this.importGroupIdentity(aidOrOptions, options));
1012
1111
  }
1013
1112
  // ── 内部辅助 ──────────────────────────────────────────────────
1014
- async _resolveGateway(aid) {
1113
+ async _resolveGateway(aid, actorAid) {
1015
1114
  const target = String(aid ?? '').trim();
1016
1115
  if (!target)
1017
1116
  throw new ValidationError('AIDStore requires non-empty aid to resolve gateway');
@@ -1024,10 +1123,13 @@ export class AIDStore {
1024
1123
  `https://${target}/.well-known/aun-gateway`,
1025
1124
  `https://gateway.${issuerDomain}/.well-known/aun-gateway`,
1026
1125
  ];
1126
+ const discovery = actorAid ? new GatewayDiscovery({ verifySsl: this._verifySsl, logger: this._log.for('aun_core.discovery'), net: this._net }) : this._discovery;
1127
+ if (actorAid)
1128
+ discovery.setHttpHandler((url, init, perform) => this._riskFetchForAid(actorAid, url, init, perform, 'http:discovery:gateway'));
1027
1129
  let lastError = null;
1028
1130
  for (const url of candidates) {
1029
1131
  try {
1030
- const discovered = await this._discovery.discover(url);
1132
+ const discovered = await discovery.discover(url);
1031
1133
  this._gatewayCache.set(issuerDomain, discovered);
1032
1134
  return discovered;
1033
1135
  }