@agentunion/fastaun 0.5.18 → 0.5.19
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 +44 -2
- package/_packed_docs/CHANGELOG.md +44 -2
- package/_packed_docs/INDEX.md +136 -14
- package/_packed_docs/KITE_DOCS_GUIDE.md +42 -16
- package/_packed_docs/agent.md/SCHEMA.md +245 -205
- package/_packed_docs/aun/345/210/206/345/270/203/345/274/217/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +42 -15
- package/_packed_docs/aun/346/265/213/350/257/225/350/277/220/350/241/214/346/214/207/345/215/227.md +4 -4
- package/_packed_docs/protocol/01-/350/272/253/344/273/275/344/270/216/345/207/255/350/257/201/345/215/217/350/256/256-auth.md +45 -134
- package/_packed_docs/protocol/07-/351/224/231/350/257/257/347/240/201/344/270/216/347/212/266/346/200/201/346/234/272.md +5 -20
- package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +28 -9
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +22 -27
- package/_packed_docs/protocol/agent.md/SCHEMA.md +4 -0
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +5 -2
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +250 -283
- package/_packed_docs/sdk/09-group-rpc-manual.md +46 -14
- package/_packed_docs/sdk/09-message-rpc-manual.md +40 -2
- package/_packed_docs/sdk/09-storage-rpc-manual.md +74 -64
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +25 -5
- package/_packed_docs/sdk/INDEX.md +76 -17
- package/dist/agent-md-schema.d.ts +2 -0
- package/dist/agent-md-schema.js +45 -10
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +47 -2
- package/dist/agent-md.js +493 -33
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +9 -59
- package/dist/aid-store.js +135 -245
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.js +19 -5
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts +6 -1
- package/dist/auth.js +428 -15
- package/dist/auth.js.map +1 -1
- package/dist/cert-utils.d.ts +1 -1
- package/dist/cert-utils.js +19 -7
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/delivery.d.ts +2 -1
- package/dist/client/delivery.js +143 -52
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.js +22 -5
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +1 -0
- package/dist/client/v2-e2ee.js +93 -29
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +84 -1
- package/dist/client.js +749 -28
- package/dist/client.js.map +1 -1
- package/dist/errors.js +4 -3
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +5 -1
- package/dist/events.js +47 -6
- package/dist/events.js.map +1 -1
- package/dist/facades.d.ts +83 -3
- package/dist/facades.js +98 -4
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/keystore/aid-db.d.ts +5 -0
- package/dist/keystore/aid-db.js +48 -0
- package/dist/keystore/aid-db.js.map +1 -1
- package/dist/keystore/index.d.ts +8 -0
- package/dist/keystore/local-identity-store.js +10 -3
- package/dist/keystore/local-identity-store.js.map +1 -1
- package/dist/keystore/local-token-store.d.ts +6 -1
- package/dist/keystore/local-token-store.js +24 -1
- package/dist/keystore/local-token-store.js.map +1 -1
- package/dist/org-protocol.d.ts +98 -0
- package/dist/org-protocol.js +1689 -0
- package/dist/org-protocol.js.map +1 -0
- package/dist/ownership-proof.d.ts +82 -5
- package/dist/ownership-proof.js +327 -31
- package/dist/ownership-proof.js.map +1 -1
- package/dist/ownership-v21.d.ts +178 -0
- package/dist/ownership-v21.js +635 -0
- package/dist/ownership-v21.js.map +1 -0
- package/dist/ownership-workflow.d.ts +82 -0
- package/dist/ownership-workflow.js +872 -0
- package/dist/ownership-workflow.js.map +1 -0
- package/dist/seq-tracker.d.ts +1 -0
- package/dist/seq-tracker.js +10 -1
- package/dist/seq-tracker.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +89 -1
- package/dist/tools/cross-sdk-agent.js +338 -7
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +7 -0
- package/dist/transport.js +108 -4
- package/dist/transport.js.map +1 -1
- package/dist/v2/e2ee/decrypt.d.ts +1 -0
- package/dist/v2/e2ee/decrypt.js +9 -1
- package/dist/v2/e2ee/decrypt.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
|
@@ -3,11 +3,15 @@ import * as http from 'node:http';
|
|
|
3
3
|
import * as https from 'node:https';
|
|
4
4
|
import * as crypto from 'node:crypto';
|
|
5
5
|
import * as fs from 'node:fs';
|
|
6
|
+
import * as path from 'node:path';
|
|
6
7
|
import { URL } from 'node:url';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
7
9
|
import { AUNClient } from '../client.js';
|
|
8
10
|
import { AIDStore } from '../aid-store.js';
|
|
9
11
|
import { publicKeyFingerprint } from '../cert-utils.js';
|
|
10
12
|
import { VERSION } from '../version.js';
|
|
13
|
+
import { canonicalJson, digest, buildRequestBinding, verifyMembershipBinding, ProtocolError } from '../org-protocol.js';
|
|
14
|
+
import { ownershipTaskResult } from '../ownership-workflow.js';
|
|
11
15
|
function envBool(name, fallback = false) {
|
|
12
16
|
const raw = process.env[name];
|
|
13
17
|
if (raw == null)
|
|
@@ -105,7 +109,7 @@ function sendJson(res, status, data) {
|
|
|
105
109
|
});
|
|
106
110
|
res.end(body);
|
|
107
111
|
}
|
|
108
|
-
class CrossSdkTsAgent {
|
|
112
|
+
export class CrossSdkTsAgent {
|
|
109
113
|
language = 'ts';
|
|
110
114
|
sdkVersion = VERSION;
|
|
111
115
|
aid = textOf(process.env.AUN_TEST_AID || 'cross-ts.agentid.pub').trim();
|
|
@@ -125,6 +129,8 @@ class CrossSdkTsAgent {
|
|
|
125
129
|
rpcObservedTransports = new WeakSet();
|
|
126
130
|
groupChangedEvents = [];
|
|
127
131
|
groupInviteEvents = [];
|
|
132
|
+
readStateEvents = [];
|
|
133
|
+
ownershipEvents = [];
|
|
128
134
|
traces = new Map();
|
|
129
135
|
sendResults = new Map();
|
|
130
136
|
inlineRealtimePayloadV1 = true;
|
|
@@ -166,6 +172,21 @@ class CrossSdkTsAgent {
|
|
|
166
172
|
});
|
|
167
173
|
this.client.on('group.changed', (data) => this.storeGroupChangedPublicEvent(data));
|
|
168
174
|
this.client.on('group.invite_received', (data) => this.storeGroupInviteEvent(data));
|
|
175
|
+
for (const event of ['message.read_changed', 'group.read_changed', 'read_state_sync']) {
|
|
176
|
+
this.client.on(event, (payload) => { this.readStateEvents.push({ event, payload: jsonSafe(payload) }); });
|
|
177
|
+
}
|
|
178
|
+
for (const event of ['ownership.request', 'ownership.pending', 'ownership.progress', 'ownership.completed', 'ownership.rejected', 'ownership.stopped', 'ownership.error', 'ownership.action_required']) {
|
|
179
|
+
this.client.on(event, (payload) => {
|
|
180
|
+
this.ownershipEvents.push({ event, payload: jsonSafe(payload) });
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
for (const suffix of ['join_requested', 'join_approved', 'join_rejected', 'invite_created', 'invite_accepted', 'invite_rejected']) {
|
|
184
|
+
const event = 'org.member.' + suffix;
|
|
185
|
+
this.client.on(event, (value) => {
|
|
186
|
+
const payload = value;
|
|
187
|
+
this.recordTrace(textOf(payload.org_id), { stage: event, payload });
|
|
188
|
+
});
|
|
189
|
+
}
|
|
169
190
|
}
|
|
170
191
|
installTransportRpcObserver() {
|
|
171
192
|
const transport = this.client._transport;
|
|
@@ -292,7 +313,14 @@ class CrossSdkTsAgent {
|
|
|
292
313
|
debug: this.debug,
|
|
293
314
|
});
|
|
294
315
|
try {
|
|
295
|
-
const
|
|
316
|
+
const fixedIdentityFile = textOf(process.env.AUN_TEST_FIXED_IDENTITY_FILE).trim();
|
|
317
|
+
if (fixedIdentityFile) {
|
|
318
|
+
const identity = JSON.parse(fs.readFileSync(fixedIdentityFile, 'utf-8'));
|
|
319
|
+
if (identity.aid !== this.aid)
|
|
320
|
+
throw new Error('固定测试身份与配置 AID 不一致');
|
|
321
|
+
store._keystore.saveIdentity(this.aid, identity);
|
|
322
|
+
}
|
|
323
|
+
const registered = fixedIdentityFile ? store.load(this.aid) : await store.register(this.aid, { type: 'service' });
|
|
296
324
|
if (!registered.ok) {
|
|
297
325
|
const loaded = store.load(this.aid);
|
|
298
326
|
if (!loaded.ok) {
|
|
@@ -301,6 +329,8 @@ class CrossSdkTsAgent {
|
|
|
301
329
|
}
|
|
302
330
|
}
|
|
303
331
|
catch (err) {
|
|
332
|
+
if (textOf(process.env.AUN_TEST_FIXED_IDENTITY_FILE).trim())
|
|
333
|
+
throw err;
|
|
304
334
|
const localIdentity = internal._auth?.loadIdentityOrNone?.(this.aid);
|
|
305
335
|
if (!localIdentity) {
|
|
306
336
|
throw new Error(`registerAid failed and no local identity exists: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -310,11 +340,15 @@ class CrossSdkTsAgent {
|
|
|
310
340
|
if (!loaded.ok) {
|
|
311
341
|
throw new Error(`load identity failed: ${loaded.error.code}: ${loaded.error.message}`);
|
|
312
342
|
}
|
|
313
|
-
const uploaded = await store.uploadAgentMd(this.aid, this.agentMdContent(this.aid, this.aid, 'agent', 'Cross-SDK TypeScript test agent'));
|
|
314
|
-
if (!uploaded.ok) {
|
|
315
|
-
throw new Error(`upload agent.md failed: ${uploaded.error.code}: ${uploaded.error.message}`);
|
|
316
|
-
}
|
|
317
343
|
this.client.loadIdentity(loaded.data.aid);
|
|
344
|
+
const checked = await store.checkAgentMd(this.aid);
|
|
345
|
+
const localEtag = checked.ok ? String(checked.data.local_etag ?? '').trim() : '';
|
|
346
|
+
const remoteEtag = checked.ok ? String(checked.data.remote_etag ?? '').trim() : '';
|
|
347
|
+
const inSync = Boolean(localEtag && remoteEtag && localEtag === remoteEtag);
|
|
348
|
+
const remoteFound = checked.ok && checked.data.remote_found === true;
|
|
349
|
+
if (!inSync && !remoteFound) {
|
|
350
|
+
await this.client._ensureInitialAgentMd();
|
|
351
|
+
}
|
|
318
352
|
this.installTransportRpcObserver();
|
|
319
353
|
await this.client.connect({ auto_reconnect: false, background_sync: backgroundSync });
|
|
320
354
|
}
|
|
@@ -330,6 +364,96 @@ class CrossSdkTsAgent {
|
|
|
330
364
|
public_key_fingerprint: cert ? publicKeyFingerprint(cert) : '',
|
|
331
365
|
};
|
|
332
366
|
}
|
|
367
|
+
async ownershipBind(req, res) {
|
|
368
|
+
const body = await readJson(req);
|
|
369
|
+
const role = textOf(body.role).trim().toLowerCase();
|
|
370
|
+
const peerAid = textOf(body.peer_aid).trim();
|
|
371
|
+
if (!['owner', 'subject'].includes(role) || !peerAid) {
|
|
372
|
+
sendJson(res, 400, { ok: false, error_code: 'bad_request', error_message: 'role and peer_aid are required' });
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
const task = role === 'owner' ? await this.client.bindSubaid(peerAid) : await this.client.bindOwneraid(peerAid);
|
|
377
|
+
sendJson(res, 200, { ok: true, operation_id: task.operation_id, task: jsonSafe(task) });
|
|
378
|
+
}
|
|
379
|
+
catch (err) {
|
|
380
|
+
sendJson(res, 500, {
|
|
381
|
+
ok: false,
|
|
382
|
+
error_code: textOf(err?.stringCode ?? err?.code ?? (err instanceof Error ? err.name : 'Error')),
|
|
383
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
async ownershipAction(req, res, action) {
|
|
388
|
+
const body = await readJson(req);
|
|
389
|
+
const operationId = textOf(body.operation_id).trim(), subAid = textOf(body.sub_aid).trim(), newOwnerAid = textOf(body.new_owner_aid).trim();
|
|
390
|
+
if ((action === 'accept' || action === 'reject') ? !operationId : !subAid || action === 'transfer' && !newOwnerAid) {
|
|
391
|
+
sendJson(res, 400, { ok: false, error_code: 'bad_request', error_message: action === 'accept' || action === 'reject' ? 'operation_id is required' : 'sub_aid and transfer new_owner_aid are required' });
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
try {
|
|
395
|
+
const task = action === 'accept' ? await this.client.acceptOwnershipRequest(operationId)
|
|
396
|
+
: action === 'reject' ? await this.client.rejectOwnershipRequest(operationId, body.reason)
|
|
397
|
+
: action === 'release' ? await this.client.releaseSubaid(subAid)
|
|
398
|
+
: await this.client.transferSubaid(subAid, newOwnerAid);
|
|
399
|
+
sendJson(res, 200, { ok: true, operation_id: task.operation_id, task: jsonSafe(task) });
|
|
400
|
+
}
|
|
401
|
+
catch (err) {
|
|
402
|
+
sendJson(res, 500, {
|
|
403
|
+
ok: false,
|
|
404
|
+
error_code: textOf(err?.stringCode ?? err?.code ?? (err instanceof Error ? err.name : 'Error')),
|
|
405
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
ownershipPublicTask(record) {
|
|
410
|
+
const decision = record.local_decision;
|
|
411
|
+
if (!['pending', 'accept', 'reject'].includes(String(decision)) || typeof record.initiator_aid !== 'string' || !record.initiator_aid)
|
|
412
|
+
throw new Error('persisted ownership approval context is unavailable');
|
|
413
|
+
return { ...ownershipTaskResult(record), initiator_aid: record.initiator_aid, local_approval: decision === 'accept' ? 'accepted' : decision === 'reject' ? 'rejected' : 'pending' };
|
|
414
|
+
}
|
|
415
|
+
async ownershipStatus(url, res) {
|
|
416
|
+
const internal = this.client;
|
|
417
|
+
if (!internal._tokenStore.listOwnershipTasks)
|
|
418
|
+
throw new Error('ownership task store is unavailable');
|
|
419
|
+
const operationId = textOf(url.searchParams.get('operation_id')).trim(), selectedSub = textOf(url.searchParams.get('sub_aid')).trim();
|
|
420
|
+
const records = internal._tokenStore.listOwnershipTasks(this.aid).map((item) => item.task).filter((record) => (!operationId || record.operation_id === operationId) && (!selectedSub || record.sub_aid === selectedSub));
|
|
421
|
+
const tasks = records.map((record) => this.ownershipPublicTask(record)), task = tasks[tasks.length - 1] ?? null;
|
|
422
|
+
const subAid = textOf(task?.sub_aid ?? selectedSub).trim() || this.aid;
|
|
423
|
+
const consensus = await this.client.checkOwnershipConsensus(subAid);
|
|
424
|
+
const files = { agent_md: null, owner_md: null, storage_agent_md: null }, fileErrors = {};
|
|
425
|
+
let nsProtocol = null;
|
|
426
|
+
try {
|
|
427
|
+
const current = await internal._getOwnershipFiles().readAgent(subAid);
|
|
428
|
+
nsProtocol = current.protocol;
|
|
429
|
+
if (!current.exists)
|
|
430
|
+
fileErrors.agent_md = 'not_found';
|
|
431
|
+
else
|
|
432
|
+
files.agent_md = { raw_base64: Buffer.from(current.content, 'utf8').toString('base64'), sha256: crypto.createHash('sha256').update(current.content, 'utf8').digest('hex'), etag: current.etag };
|
|
433
|
+
}
|
|
434
|
+
catch (err) {
|
|
435
|
+
fileErrors.agent_md = err instanceof Error ? err.message : String(err);
|
|
436
|
+
}
|
|
437
|
+
const ownerAid = textOf(task?.operation === 'release' ? task.owner_aid : consensus.owner_aid ?? task?.new_owner_aid ?? task?.owner_aid).trim();
|
|
438
|
+
const readStorageFile = async (name, read) => {
|
|
439
|
+
try {
|
|
440
|
+
const current = await read();
|
|
441
|
+
if (!current.exists)
|
|
442
|
+
fileErrors[name] = 'not_found';
|
|
443
|
+
else
|
|
444
|
+
files[name] = { raw_base64: Buffer.from(current.content, 'utf8').toString('base64'), sha256: crypto.createHash('sha256').update(current.content, 'utf8').digest('hex'), revision: current.revision };
|
|
445
|
+
}
|
|
446
|
+
catch (err) {
|
|
447
|
+
fileErrors[name] = err instanceof Error ? err.message : String(err);
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
await Promise.all([
|
|
451
|
+
ownerAid ? readStorageFile('owner_md', () => internal._getOwnershipFiles().readOwner(ownerAid, subAid)) : Promise.resolve().then(() => { fileErrors.owner_md = 'owner_aid is unavailable'; }),
|
|
452
|
+
readStorageFile('storage_agent_md', () => internal._getOwnershipStorage().readObject(subAid, 'agent.md')),
|
|
453
|
+
]);
|
|
454
|
+
const events = this.ownershipEvents.filter((item) => (!operationId || item.payload?.operation_id === operationId) && (!selectedSub || item.payload?.sub_aid === selectedSub));
|
|
455
|
+
sendJson(res, 200, { ok: true, task, tasks, events, consensus: consensus, files, file_errors: fileErrors, ns_protocol: nsProtocol });
|
|
456
|
+
}
|
|
333
457
|
recordTrace(traceId, item) {
|
|
334
458
|
if (!traceId)
|
|
335
459
|
return;
|
|
@@ -439,6 +563,7 @@ class CrossSdkTsAgent {
|
|
|
439
563
|
this.rawPushRpcMethods = [];
|
|
440
564
|
this.groupChangedEvents = [];
|
|
441
565
|
this.groupInviteEvents = [];
|
|
566
|
+
this.readStateEvents = [];
|
|
442
567
|
this.rawPushObservationId = textOf(body.observation_id ?? '');
|
|
443
568
|
sendJson(res, 200, { ok: true, observation_id: this.rawPushObservationId });
|
|
444
569
|
return;
|
|
@@ -477,6 +602,7 @@ class CrossSdkTsAgent {
|
|
|
477
602
|
rpc_calls: rpcEntries,
|
|
478
603
|
group_changed_events: groupChangedEvents.slice(-limit),
|
|
479
604
|
group_invite_events: groupInviteEvents.slice(-limit),
|
|
605
|
+
read_state_events: this.readStateEvents.slice(-limit),
|
|
480
606
|
});
|
|
481
607
|
return;
|
|
482
608
|
}
|
|
@@ -484,6 +610,34 @@ class CrossSdkTsAgent {
|
|
|
484
610
|
sendJson(res, 200, this.identity());
|
|
485
611
|
return;
|
|
486
612
|
}
|
|
613
|
+
if (req.method === 'POST' && url.pathname === '/ownership/bind') {
|
|
614
|
+
await this.ownershipBind(req, res);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
if (req.method === 'POST' && url.pathname === '/ownership/accept') {
|
|
618
|
+
await this.ownershipAction(req, res, 'accept');
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
if (req.method === 'POST' && url.pathname === '/ownership/reject') {
|
|
622
|
+
await this.ownershipAction(req, res, 'reject');
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
if (req.method === 'POST' && url.pathname === '/ownership/release') {
|
|
626
|
+
await this.ownershipAction(req, res, 'release');
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
if (req.method === 'POST' && url.pathname === '/ownership/transfer') {
|
|
630
|
+
await this.ownershipAction(req, res, 'transfer');
|
|
631
|
+
return;
|
|
632
|
+
}
|
|
633
|
+
if (req.method === 'GET' && url.pathname === '/ownership/status') {
|
|
634
|
+
await this.ownershipStatus(url, res);
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
if (req.method === 'GET' && url.pathname === '/ownership/events') {
|
|
638
|
+
sendJson(res, 200, { ok: true, events: this.ownershipEvents });
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
487
641
|
if (req.method === 'POST' && url.pathname === '/send') {
|
|
488
642
|
await this.send(req, res);
|
|
489
643
|
return;
|
|
@@ -496,6 +650,10 @@ class CrossSdkTsAgent {
|
|
|
496
650
|
await this.pull(req, res);
|
|
497
651
|
return;
|
|
498
652
|
}
|
|
653
|
+
if (req.method === 'POST' && url.pathname === '/message/call') {
|
|
654
|
+
await this.messageCall(req, res);
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
499
657
|
if (req.method === 'GET' && url.pathname === '/sync/state') {
|
|
500
658
|
this.syncState(url, res);
|
|
501
659
|
return;
|
|
@@ -721,6 +879,39 @@ class CrossSdkTsAgent {
|
|
|
721
879
|
});
|
|
722
880
|
}
|
|
723
881
|
}
|
|
882
|
+
async messageCall(req, res) {
|
|
883
|
+
const body = await readJson(req);
|
|
884
|
+
const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
|
|
885
|
+
const method = textOf(body.method).trim();
|
|
886
|
+
const params = jsonObjectOf(body.params) ?? {};
|
|
887
|
+
if (!method) {
|
|
888
|
+
sendJson(res, 400, { ok: false, trace_id: traceId, error_code: 'bad_request', error_message: 'method is required' });
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
try {
|
|
892
|
+
let result;
|
|
893
|
+
if (method === 'message.read')
|
|
894
|
+
result = await this.client.message.read(params);
|
|
895
|
+
else if (method === 'message.read_state')
|
|
896
|
+
result = await this.client.message.readState(params);
|
|
897
|
+
else
|
|
898
|
+
result = await this.client.call(method, params);
|
|
899
|
+
const response = { ok: true, trace_id: traceId, method, result: jsonSafe(result) };
|
|
900
|
+
this.recordTrace(traceId, { stage: 'message_call', method, result: response });
|
|
901
|
+
sendJson(res, 200, response);
|
|
902
|
+
}
|
|
903
|
+
catch (err) {
|
|
904
|
+
const error = {
|
|
905
|
+
ok: false,
|
|
906
|
+
trace_id: traceId,
|
|
907
|
+
method,
|
|
908
|
+
error_code: err instanceof Error ? err.name : 'Error',
|
|
909
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
910
|
+
};
|
|
911
|
+
this.recordTrace(traceId, { stage: 'message_call_error', method, error });
|
|
912
|
+
sendJson(res, 500, error);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
724
915
|
syncNamespace(scope, groupId = '') {
|
|
725
916
|
if (scope === 'p2p')
|
|
726
917
|
return `p2p:${this.aid}`;
|
|
@@ -940,6 +1131,76 @@ class CrossSdkTsAgent {
|
|
|
940
1131
|
store.close();
|
|
941
1132
|
}
|
|
942
1133
|
}
|
|
1134
|
+
async orgProtocol(params) {
|
|
1135
|
+
const op = textOf(params.op);
|
|
1136
|
+
const now = Math.floor(Date.now() / 1000);
|
|
1137
|
+
if (op === 'request')
|
|
1138
|
+
return buildRequestBinding(textOf(params.method), textOf(params.target), params.params, textOf(params.credential_cid), textOf(params.nonce), textOf(params.request_id), now, now + 300);
|
|
1139
|
+
if (['register', 'sign', 'certificate', 'create'].includes(op)) {
|
|
1140
|
+
const store = this.aidStore();
|
|
1141
|
+
try {
|
|
1142
|
+
if (op === 'register') {
|
|
1143
|
+
const registered = await store.register(textOf(params.org_id), { type: 'org', owner: this.aid, exttype: 'company' });
|
|
1144
|
+
if (!registered.ok)
|
|
1145
|
+
throw new Error(String(registered.error));
|
|
1146
|
+
}
|
|
1147
|
+
const loaded = op === 'certificate'
|
|
1148
|
+
? await store.resolve(textOf(params.as_aid), { skipAgentMd: true })
|
|
1149
|
+
: (params.as_aid || params.org_id) ? store.load(textOf(params.as_aid ?? params.org_id)) : null;
|
|
1150
|
+
if (loaded && !loaded.ok)
|
|
1151
|
+
throw new Error(String(loaded.error));
|
|
1152
|
+
const identity = loaded?.data?.aid ?? this.client.currentAid;
|
|
1153
|
+
const result = { cert_fingerprint: identity.certFingerprint, certificate: identity.certPem };
|
|
1154
|
+
if (op === 'sign') {
|
|
1155
|
+
const signed = await identity.sign(Buffer.from(canonicalJson(params.payload)));
|
|
1156
|
+
if (!signed.ok)
|
|
1157
|
+
throw new Error(String(signed.error));
|
|
1158
|
+
result.signature = { cert_fingerprint: identity.certFingerprint, timestamp: now, signature: signed.data.signature };
|
|
1159
|
+
}
|
|
1160
|
+
else if (op === 'create') {
|
|
1161
|
+
result.credential = params.membership_binding
|
|
1162
|
+
? this.client.org.member.createCredential(params.membership_binding, identity, params.options)
|
|
1163
|
+
: this.client.credential.create(params.options, identity);
|
|
1164
|
+
}
|
|
1165
|
+
return result;
|
|
1166
|
+
}
|
|
1167
|
+
finally {
|
|
1168
|
+
store.close();
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
const value = params.document ?? params.payload;
|
|
1172
|
+
const result = { canonical: new TextDecoder().decode(canonicalJson(value)), digest: digest(value), error_code: '' };
|
|
1173
|
+
if (op === 'verify' || op === 'verify_full') {
|
|
1174
|
+
const certificates = params.certificates;
|
|
1175
|
+
const resolver = (fingerprint) => certificates[fingerprint];
|
|
1176
|
+
try {
|
|
1177
|
+
if (op === 'verify_full') {
|
|
1178
|
+
const actual = jsonObjectOf(params.context) ?? params;
|
|
1179
|
+
const memberships = jsonObjectOf(params.memberships) ?? {};
|
|
1180
|
+
result.verification = { ...this.client.credential.verify(value, { resolveCertificate: resolver, resolveActorCertificate: resolver,
|
|
1181
|
+
resolveStatus: (cid) => params.statuses?.[cid], now, audience: textOf(actual.audience), subject: textOf(actual.subject) || undefined,
|
|
1182
|
+
ns: textOf(actual.ns), action: textOf(actual.action), resource: textOf(actual.resource), rootIssuer: textOf(actual.root_issuer) || undefined,
|
|
1183
|
+
params: jsonObjectOf(actual.params) ?? {}, units: jsonObjectOf(actual.units) ?? {}, clientIp: textOf(actual.client_ip), method: textOf(actual.method), target: textOf(actual.target),
|
|
1184
|
+
requestId: textOf(actual.request_id), nonce: textOf(actual.nonce), requestBinding: actual.request_binding, proofChain: actual.proof_chain, membershipBinding: actual.membership_binding,
|
|
1185
|
+
orgSigner: textOf(actual.org_signer) || undefined, actor: textOf(actual.actor) || undefined, for: textOf(actual.for) || undefined, representationProof: actual.representation_proof,
|
|
1186
|
+
resolveMembershipStatus: (binding, credential) => { const current = jsonObjectOf(memberships[String(binding.membership_id)]); return current?.status === 'active' && current.credential_cid === credential.cid; },
|
|
1187
|
+
resolveOwnership: (subject, owner) => (jsonObjectOf(params.ownerships) ?? {})[subject] === owner, checkRateLimit: () => params.rate_limit_allowed === true }) };
|
|
1188
|
+
}
|
|
1189
|
+
else if (params.kind === 'credential')
|
|
1190
|
+
result.verification = { ...this.client.credential.verifySignature(value, resolver, now, textOf(params.audience)) };
|
|
1191
|
+
else if (params.kind === 'binding')
|
|
1192
|
+
await verifyMembershipBinding(value, resolver, now, textOf(params.expected_org_signer));
|
|
1193
|
+
else
|
|
1194
|
+
result.verification = { ...this.client.credential.verifyRegistrationReceipt(value, params.credential, params.request, resolver, textOf(params.service_aid), now) };
|
|
1195
|
+
}
|
|
1196
|
+
catch (error) {
|
|
1197
|
+
if (!(error instanceof ProtocolError))
|
|
1198
|
+
throw error;
|
|
1199
|
+
result.error_code = error.code;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
return result;
|
|
1203
|
+
}
|
|
943
1204
|
async groupCall(req, res) {
|
|
944
1205
|
const body = await readJson(req);
|
|
945
1206
|
const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
|
|
@@ -955,6 +1216,48 @@ class CrossSdkTsAgent {
|
|
|
955
1216
|
try {
|
|
956
1217
|
let result;
|
|
957
1218
|
switch (method) {
|
|
1219
|
+
case 'sdk.org.protocol':
|
|
1220
|
+
result = await this.orgProtocol(params);
|
|
1221
|
+
break;
|
|
1222
|
+
case 'org.lifecycle.create':
|
|
1223
|
+
result = await this.client.org.lifecycle.create(params);
|
|
1224
|
+
break;
|
|
1225
|
+
case 'org.lifecycle.dissolve':
|
|
1226
|
+
result = await this.client.org.lifecycle.dissolve(params);
|
|
1227
|
+
break;
|
|
1228
|
+
case 'org.lifecycle.transfer':
|
|
1229
|
+
result = await this.client.org.lifecycle.transfer(params);
|
|
1230
|
+
break;
|
|
1231
|
+
case 'org.lifecycle.transferAccept':
|
|
1232
|
+
result = await this.client.org.lifecycle.transferAccept(params);
|
|
1233
|
+
break;
|
|
1234
|
+
case 'org.member.join':
|
|
1235
|
+
result = await this.client.org.member.join(params);
|
|
1236
|
+
break;
|
|
1237
|
+
case 'org.member.approveJoin':
|
|
1238
|
+
result = await this.client.org.member.approveJoin(params);
|
|
1239
|
+
break;
|
|
1240
|
+
case 'org.member.rejectJoin':
|
|
1241
|
+
result = await this.client.org.member.rejectJoin(params);
|
|
1242
|
+
break;
|
|
1243
|
+
case 'org.member.invite':
|
|
1244
|
+
result = await this.client.org.member.invite(params);
|
|
1245
|
+
break;
|
|
1246
|
+
case 'org.member.inviteAccept':
|
|
1247
|
+
result = await this.client.org.member.inviteAccept(params);
|
|
1248
|
+
break;
|
|
1249
|
+
case 'org.member.inviteReject':
|
|
1250
|
+
result = await this.client.org.member.inviteReject(params);
|
|
1251
|
+
break;
|
|
1252
|
+
case 'org.member.leave':
|
|
1253
|
+
result = await this.client.org.member.leave(params);
|
|
1254
|
+
break;
|
|
1255
|
+
case 'org.member.offboard':
|
|
1256
|
+
result = await this.client.org.member.offboard(params);
|
|
1257
|
+
break;
|
|
1258
|
+
case 'org.credential.getStatus':
|
|
1259
|
+
result = await this.client.org.credential.getStatus(params);
|
|
1260
|
+
break;
|
|
958
1261
|
case 'sdk.update_group_index':
|
|
959
1262
|
result = await this.client.group.updateGroupIndex(params);
|
|
960
1263
|
break;
|
|
@@ -988,6 +1291,12 @@ class CrossSdkTsAgent {
|
|
|
988
1291
|
case 'group.get_member_statuses':
|
|
989
1292
|
result = await this.client.group.getMemberStatuses(params);
|
|
990
1293
|
break;
|
|
1294
|
+
case 'group.read':
|
|
1295
|
+
result = await this.client.group.read(params);
|
|
1296
|
+
break;
|
|
1297
|
+
case 'group.read_state':
|
|
1298
|
+
result = await this.client.group.readState(params);
|
|
1299
|
+
break;
|
|
991
1300
|
default: result = await this.client.call(method, params);
|
|
992
1301
|
}
|
|
993
1302
|
const response = { ok: true, trace_id: traceId, method, result: jsonSafe(result) };
|
|
@@ -1750,6 +2059,27 @@ class CrossSdkTsAgent {
|
|
|
1750
2059
|
'',
|
|
1751
2060
|
].join('\n');
|
|
1752
2061
|
}
|
|
2062
|
+
agentMdContentForUpload(aid, name, type, description) {
|
|
2063
|
+
let content = '';
|
|
2064
|
+
try {
|
|
2065
|
+
const manager = this.client._agentMdManager;
|
|
2066
|
+
const managed = manager?.readContent?.(aid);
|
|
2067
|
+
content = typeof managed === 'string' ? managed : '';
|
|
2068
|
+
}
|
|
2069
|
+
catch {
|
|
2070
|
+
content = '';
|
|
2071
|
+
}
|
|
2072
|
+
if (content && (content.includes('owner:') || content.includes('ownership_proof:') || content.includes('ownership_release:')))
|
|
2073
|
+
return content;
|
|
2074
|
+
try {
|
|
2075
|
+
content = fs.readFileSync(path.join(this.aunPath, 'AIDs', aid, 'agent.md'), 'utf-8');
|
|
2076
|
+
if (content.includes('owner:') || content.includes('ownership_proof:') || content.includes('ownership_release:'))
|
|
2077
|
+
return content;
|
|
2078
|
+
}
|
|
2079
|
+
catch {
|
|
2080
|
+
}
|
|
2081
|
+
return this.agentMdContent(aid, name, type, description);
|
|
2082
|
+
}
|
|
1753
2083
|
aidStore() {
|
|
1754
2084
|
return new AIDStore({
|
|
1755
2085
|
aunPath: this.aunPath,
|
|
@@ -1834,5 +2164,6 @@ async function main() {
|
|
|
1834
2164
|
process.on('SIGINT', () => { void shutdown(); });
|
|
1835
2165
|
process.on('SIGTERM', () => { void shutdown(); });
|
|
1836
2166
|
}
|
|
1837
|
-
|
|
2167
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url))
|
|
2168
|
+
void main();
|
|
1838
2169
|
//# sourceMappingURL=cross-sdk-agent.js.map
|