@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.
- package/CHANGELOG.md +69 -1
- package/_packed_docs/CHANGELOG.md +69 -1
- 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
- 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
- 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
- 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
- package/_packed_docs/sdk/09-storage-rpc-manual.md +33 -16
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +12 -5
- 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
- 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
- package/_packed_docs/sdk/INDEX.md +27 -5
- 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
- package/dist/agent-md.d.ts +2 -1
- package/dist/agent-md.js +17 -0
- package/dist/agent-md.js.map +1 -1
- package/dist/client/control-messages.d.ts +22 -6
- package/dist/client/control-messages.js +210 -148
- package/dist/client/control-messages.js.map +1 -1
- package/dist/client/delivery.d.ts +3 -0
- package/dist/client/delivery.js +67 -3
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/group-state.d.ts +3 -0
- package/dist/client/group-state.js +48 -14
- package/dist/client/group-state.js.map +1 -1
- package/dist/client/lifecycle.js +3 -2
- package/dist/client/lifecycle.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts +9 -3
- package/dist/client/rpc-pipeline.js +80 -27
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +13 -1
- package/dist/client/v2-e2ee.js +32 -19
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +13 -5
- package/dist/client.js +121 -37
- package/dist/client.js.map +1 -1
- package/dist/group-fs.js +1 -1
- package/dist/group-fs.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/ownership-workflow.d.ts +23 -3
- package/dist/ownership-workflow.js +39 -16
- package/dist/ownership-workflow.js.map +1 -1
- package/dist/pubsub/binding.d.ts +54 -0
- package/dist/pubsub/binding.js +343 -0
- package/dist/pubsub/binding.js.map +1 -0
- package/dist/pubsub/channel.d.ts +45 -0
- package/dist/pubsub/channel.js +137 -0
- package/dist/pubsub/channel.js.map +1 -0
- package/dist/pubsub/client.d.ts +93 -0
- package/dist/pubsub/client.js +318 -0
- package/dist/pubsub/client.js.map +1 -0
- package/dist/pubsub/credentials.d.ts +51 -0
- package/dist/pubsub/credentials.js +360 -0
- package/dist/pubsub/credentials.js.map +1 -0
- package/dist/pubsub/errors.d.ts +5 -0
- package/dist/pubsub/errors.js +6 -0
- package/dist/pubsub/errors.js.map +1 -0
- package/dist/pubsub/index.d.ts +48 -0
- package/dist/pubsub/index.js +152 -0
- package/dist/pubsub/index.js.map +1 -0
- package/dist/pubsub/scheduler.d.ts +58 -0
- package/dist/pubsub/scheduler.js +249 -0
- package/dist/pubsub/scheduler.js.map +1 -0
- package/dist/pubsub/service.d.ts +100 -0
- package/dist/pubsub/service.js +650 -0
- package/dist/pubsub/service.js.map +1 -0
- package/dist/pubsub/types.d.ts +119 -0
- package/dist/pubsub/types.js +2 -0
- package/dist/pubsub/types.js.map +1 -0
- package/dist/storage/lowlevel.d.ts +4 -2
- package/dist/storage/lowlevel.js +46 -7
- package/dist/storage/lowlevel.js.map +1 -1
- package/dist/storage/read-cache.d.ts +7 -3
- package/dist/storage/read-cache.js +149 -18
- package/dist/storage/read-cache.js.map +1 -1
- package/dist/storage/vfs.d.ts +5 -2
- package/dist/storage/vfs.js +13 -3
- package/dist/storage/vfs.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +8 -2
- package/dist/tools/cross-sdk-agent.js +81 -16
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/tools/pubsub-actor.d.ts +27 -0
- package/dist/tools/pubsub-actor.js +260 -0
- package/dist/tools/pubsub-actor.js.map +1 -0
- package/dist/transport.d.ts +25 -1
- package/dist/transport.js +175 -10
- package/dist/transport.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- 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) => {
|
|
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
|
-
|
|
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()
|
|
1334
|
-
throw ownershipFailure('forbidden', 'local ownership requires a distinct
|
|
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 (
|
|
1347
|
-
throw ownershipFailure('forbidden', 'local ownership requires
|
|
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
|
|
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
|
|
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
|
|
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
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
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}`);
|