@agentunion/fastaun-browser 0.5.18 → 0.5.20
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 +172 -79
- package/_packed_docs/CHANGELOG.md +172 -79
- package/_packed_docs/INDEX.md +244 -116
- package/_packed_docs/KITE_DOCS_GUIDE.md +98 -69
- package/_packed_docs/agent.md/SCHEMA.md +245 -205
- package/_packed_docs/agent.md//350/277/234/347/250/213agent.md/347/274/223/345/255/230/344/270/216etag/351/200/217/344/274/240/346/226/271/346/241/210.md +11 -11
- 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/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1072 -1072
- 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 +687 -668
- package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +19 -28
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +443 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +658 -0
- package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
- package/_packed_docs/protocol/agent.md/SCHEMA.md +4 -0
- package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +1 -1
- package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +68 -61
- package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +1 -1
- package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +279 -285
- package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
- package/_packed_docs/sdk/09-group-rpc-manual.md +271 -235
- package/_packed_docs/sdk/09-message-rpc-manual.md +47 -6
- package/_packed_docs/sdk/09-storage-rpc-manual.md +70 -68
- package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +63 -34
- package/_packed_docs/sdk/INDEX.md +105 -34
- package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
- package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +922 -0
- package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
- package/_packed_docs/sdk/Ownership2.1-SDK/345/272/224/347/224/250/351/233/206/346/210/220/346/214/207/345/215/227.md +300 -0
- package/_packed_docs/sdk/Ownership2.1-SDK/345/274/200/345/217/221/344/270/216/347/247/273/346/244/215/346/214/207/345/215/227.md +382 -0
- package/_packed_docs/sdk/Ownership2.1-TDD/345/210/206/351/230/266/346/256/265/345/256/236/346/226/275/350/256/241/345/210/222.md +708 -0
- package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +476 -0
- package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
- package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
- 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 +173 -0
- 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 +211 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/345/256/236/347/216/260/347/247/273/346/244/215/346/214/207/345/215/227.md +331 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +207 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/344/273/243/347/240/201/345/256/241/346/237/245/346/212/245/345/221/212.md +252 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/345/256/236/346/226/275/350/256/241/345/210/222.md +156 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/346/226/271/346/241/210.md +273 -0
- package/_packed_docs//350/267/250/350/256/276/345/244/207/345/267/262/350/257/273/346/234/252/350/257/273/350/257/246/347/273/206/350/256/276/350/256/241.md +211 -0
- package/dist/agent-md-schema.d.ts +17 -3
- package/dist/agent-md-schema.d.ts.map +1 -1
- package/dist/agent-md-schema.js +94 -26
- package/dist/agent-md-schema.js.map +1 -1
- package/dist/agent-md.d.ts +54 -3
- package/dist/agent-md.d.ts.map +1 -1
- package/dist/agent-md.js +711 -65
- package/dist/agent-md.js.map +1 -1
- package/dist/aid-store.d.ts +58 -46
- package/dist/aid-store.d.ts.map +1 -1
- package/dist/aid-store.js +254 -248
- package/dist/aid-store.js.map +1 -1
- package/dist/aid.d.ts +4 -1
- package/dist/aid.d.ts.map +1 -1
- package/dist/aid.js +27 -33
- package/dist/aid.js.map +1 -1
- package/dist/auth.d.ts +4 -1
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +426 -39
- package/dist/auth.js.map +1 -1
- package/dist/bundle.js +38179 -32054
- package/dist/cert-utils.d.ts +50 -2
- package/dist/cert-utils.d.ts.map +1 -1
- package/dist/cert-utils.js +105 -47
- package/dist/cert-utils.js.map +1 -1
- package/dist/client/delivery.d.ts +22 -1
- package/dist/client/delivery.d.ts.map +1 -1
- package/dist/client/delivery.js +389 -78
- package/dist/client/delivery.js.map +1 -1
- package/dist/client/rpc-pipeline.d.ts.map +1 -1
- package/dist/client/rpc-pipeline.js +103 -77
- package/dist/client/rpc-pipeline.js.map +1 -1
- package/dist/client/v2-e2ee.d.ts +1 -0
- package/dist/client/v2-e2ee.d.ts.map +1 -1
- package/dist/client/v2-e2ee.js +182 -89
- package/dist/client/v2-e2ee.js.map +1 -1
- package/dist/client.d.ts +100 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1220 -25
- package/dist/client.js.map +1 -1
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +8 -6
- package/dist/crypto.js.map +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -2
- package/dist/errors.js.map +1 -1
- package/dist/events.d.ts +9 -2
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +72 -13
- package/dist/events.js.map +1 -1
- package/dist/facades.d.ts +82 -2
- package/dist/facades.d.ts.map +1 -1
- package/dist/facades.js +100 -6
- package/dist/facades.js.map +1 -1
- package/dist/index.d.ts +7 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/keystore/index.d.ts +17 -0
- package/dist/keystore/index.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.d.ts +10 -1
- package/dist/keystore/indexeddb-shared.d.ts.map +1 -1
- package/dist/keystore/indexeddb-shared.js +111 -0
- package/dist/keystore/indexeddb-shared.js.map +1 -1
- package/dist/keystore/indexeddb-token-store.d.ts +7 -1
- package/dist/keystore/indexeddb-token-store.d.ts.map +1 -1
- package/dist/keystore/indexeddb-token-store.js +30 -1
- package/dist/keystore/indexeddb-token-store.js.map +1 -1
- package/dist/org-protocol.d.ts +98 -0
- package/dist/org-protocol.d.ts.map +1 -0
- package/dist/org-protocol.js +1802 -0
- package/dist/org-protocol.js.map +1 -0
- package/dist/ownership-proof.d.ts +93 -5
- package/dist/ownership-proof.d.ts.map +1 -1
- package/dist/ownership-proof.js +239 -53
- package/dist/ownership-proof.js.map +1 -1
- package/dist/ownership-v21.d.ts +194 -0
- package/dist/ownership-v21.d.ts.map +1 -0
- package/dist/ownership-v21.js +678 -0
- package/dist/ownership-v21.js.map +1 -0
- package/dist/ownership-workflow.d.ts +151 -0
- package/dist/ownership-workflow.d.ts.map +1 -0
- package/dist/ownership-workflow.js +1229 -0
- package/dist/ownership-workflow.js.map +1 -0
- package/dist/seq-tracker.d.ts +1 -0
- package/dist/seq-tracker.d.ts.map +1 -1
- package/dist/seq-tracker.js +10 -2
- package/dist/seq-tracker.js.map +1 -1
- package/dist/tools/cross-sdk-agent.d.ts +83 -0
- package/dist/tools/cross-sdk-agent.d.ts.map +1 -1
- package/dist/tools/cross-sdk-agent.js +415 -7
- package/dist/tools/cross-sdk-agent.js.map +1 -1
- package/dist/transport.d.ts +7 -0
- package/dist/transport.d.ts.map +1 -1
- package/dist/transport.js +90 -2
- package/dist/transport.js.map +1 -1
- package/dist/v2/e2ee/decrypt.d.ts +1 -0
- package/dist/v2/e2ee/decrypt.d.ts.map +1 -1
- 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
|
@@ -4,9 +4,14 @@ import * as http from 'node:http';
|
|
|
4
4
|
import * as https from 'node:https';
|
|
5
5
|
import * as crypto from 'node:crypto';
|
|
6
6
|
import * as fs from 'node:fs';
|
|
7
|
-
import
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { URL, fileURLToPath } from 'node:url';
|
|
8
9
|
import { AID, AIDStore, AUNClient, __version__ } from '../index.js';
|
|
9
10
|
import { publicKeyFingerprint } from '../cert-utils.js';
|
|
11
|
+
import { StateError } from '../errors.js';
|
|
12
|
+
import { OwnershipStorageAdapter } from '../ownership-v21.js';
|
|
13
|
+
import { ownershipErrorCode, ownershipTaskResult } from '../ownership-workflow.js';
|
|
14
|
+
import { canonicalJson, digest, buildRequestBinding, verifyMembershipBinding, ProtocolError } from '../org-protocol.js';
|
|
10
15
|
function installNodeBrowserShims() {
|
|
11
16
|
const root = globalThis;
|
|
12
17
|
if (!root.WebSocket)
|
|
@@ -120,7 +125,7 @@ function envelopeMetadata(data) {
|
|
|
120
125
|
out.protected_headers = jsonSafe(protectedHeaders);
|
|
121
126
|
return out;
|
|
122
127
|
}
|
|
123
|
-
class CrossSdkJsAgent {
|
|
128
|
+
export class CrossSdkJsAgent {
|
|
124
129
|
language = 'js';
|
|
125
130
|
sdkVersion = __version__;
|
|
126
131
|
aid = textOf(process.env.AUN_TEST_AID || `cross-js-${crypto.randomUUID().slice(0, 8)}.agentid.pub`).trim();
|
|
@@ -139,6 +144,8 @@ class CrossSdkJsAgent {
|
|
|
139
144
|
rpcObservedTransports = new WeakSet();
|
|
140
145
|
groupChangedEvents = [];
|
|
141
146
|
groupInviteEvents = [];
|
|
147
|
+
readStateEvents = [];
|
|
148
|
+
ownershipEvents = [];
|
|
142
149
|
traces = new Map();
|
|
143
150
|
sendResults = new Map();
|
|
144
151
|
inlineRealtimePayloadV1 = true;
|
|
@@ -178,6 +185,19 @@ class CrossSdkJsAgent {
|
|
|
178
185
|
});
|
|
179
186
|
this.client.on('group.changed', (data) => this.storeGroupChangedPublicEvent(data));
|
|
180
187
|
this.client.on('group.invite_received', (data) => this.storeGroupInviteEvent(data));
|
|
188
|
+
for (const event of ['message.read_changed', 'group.read_changed', 'read_state_sync']) {
|
|
189
|
+
this.client.on(event, (payload) => { this.readStateEvents.push({ event, payload: jsonSafe(payload) }); });
|
|
190
|
+
}
|
|
191
|
+
for (const event of ['ownership.request', 'ownership.action_required', 'ownership.progress', 'ownership.completed', 'ownership.rejected', 'ownership.stopped', 'ownership.error']) {
|
|
192
|
+
this.client.on(event, (payload) => { this.ownershipEvents.push({ event, payload: jsonSafe(payload) }); });
|
|
193
|
+
}
|
|
194
|
+
for (const suffix of ['join_requested', 'join_approved', 'join_rejected', 'invite_created', 'invite_accepted', 'invite_rejected']) {
|
|
195
|
+
const event = 'org.member.' + suffix;
|
|
196
|
+
this.client.on(event, (value) => {
|
|
197
|
+
const payload = value;
|
|
198
|
+
this.recordTrace(textOf(payload.org_id), { stage: event, payload });
|
|
199
|
+
});
|
|
200
|
+
}
|
|
181
201
|
}
|
|
182
202
|
installTransportRpcObserver() {
|
|
183
203
|
const transport = this.client._transport;
|
|
@@ -317,10 +337,38 @@ class CrossSdkJsAgent {
|
|
|
317
337
|
'',
|
|
318
338
|
].join('\n');
|
|
319
339
|
}
|
|
340
|
+
async agentMdContentForUpload(aid, name, type, description) {
|
|
341
|
+
let content = '';
|
|
342
|
+
try {
|
|
343
|
+
const manager = this.client._agentMdManager;
|
|
344
|
+
const managed = await Promise.resolve(manager?.readContent?.(aid));
|
|
345
|
+
content = typeof managed === 'string' ? managed : '';
|
|
346
|
+
}
|
|
347
|
+
catch {
|
|
348
|
+
content = '';
|
|
349
|
+
}
|
|
350
|
+
if (content && (content.includes('owner:') || content.includes('ownership_proof:') || content.includes('ownership_release:')))
|
|
351
|
+
return content;
|
|
352
|
+
try {
|
|
353
|
+
content = fs.readFileSync(path.join(this.aunPath, 'AIDs', aid, 'agent.md'), 'utf-8');
|
|
354
|
+
if (content.includes('owner:') || content.includes('ownership_proof:') || content.includes('ownership_release:'))
|
|
355
|
+
return content;
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
}
|
|
359
|
+
return this.agentMdContent(aid, name, type, description);
|
|
360
|
+
}
|
|
320
361
|
async ensureConnected(backgroundSync = true) {
|
|
321
362
|
const store = this.aidStore();
|
|
322
363
|
try {
|
|
323
|
-
const
|
|
364
|
+
const fixedIdentityFile = textOf(process.env.AUN_TEST_FIXED_IDENTITY_FILE).trim();
|
|
365
|
+
if (fixedIdentityFile) {
|
|
366
|
+
const identity = JSON.parse(fs.readFileSync(fixedIdentityFile, 'utf-8'));
|
|
367
|
+
if (identity.aid !== this.aid)
|
|
368
|
+
throw new Error('固定测试身份与配置 AID 不一致');
|
|
369
|
+
await store._keystore.saveIdentity(this.aid, identity);
|
|
370
|
+
}
|
|
371
|
+
const registered = fixedIdentityFile ? await store.load(this.aid) : await store.register(this.aid, { type: 'service' });
|
|
324
372
|
if (!registered.ok) {
|
|
325
373
|
const loaded = await store.load(this.aid);
|
|
326
374
|
if (!loaded.ok) {
|
|
@@ -331,9 +379,16 @@ class CrossSdkJsAgent {
|
|
|
331
379
|
if (!loaded.ok) {
|
|
332
380
|
throw new Error(`load identity failed: ${loaded.error.code}: ${loaded.error.message}`);
|
|
333
381
|
}
|
|
334
|
-
const
|
|
335
|
-
|
|
336
|
-
|
|
382
|
+
const checked = await store.checkAgentMd(this.aid);
|
|
383
|
+
const localEtag = checked.ok ? String(checked.data.local_etag ?? '').trim() : '';
|
|
384
|
+
const remoteEtag = checked.ok ? String(checked.data.remote_etag ?? '').trim() : '';
|
|
385
|
+
const inSync = Boolean(localEtag && remoteEtag && localEtag === remoteEtag);
|
|
386
|
+
const remoteFound = checked.ok && checked.data.remote_found === true;
|
|
387
|
+
if (!inSync && !remoteFound) {
|
|
388
|
+
const uploaded = await store.uploadAgentMd(this.aid, await this.agentMdContentForUpload(this.aid, this.aid, 'agent', 'Cross-SDK JavaScript test agent'));
|
|
389
|
+
if (!uploaded.ok) {
|
|
390
|
+
throw new Error(`upload agent.md failed: ${uploaded.error.code}: ${uploaded.error.message}`);
|
|
391
|
+
}
|
|
337
392
|
}
|
|
338
393
|
let identity = loaded.data.aid;
|
|
339
394
|
if (this.debug && !identity.debug) {
|
|
@@ -439,6 +494,106 @@ class CrossSdkJsAgent {
|
|
|
439
494
|
...envelopeMetadata(data),
|
|
440
495
|
};
|
|
441
496
|
}
|
|
497
|
+
async ownershipControl(req, res, action) {
|
|
498
|
+
const body = await readJson(req);
|
|
499
|
+
const required = { bind: ['role', 'peer_aid'], accept: ['operation_id'], reject: ['operation_id'], release: ['sub_aid'], transfer: ['sub_aid', 'new_owner_aid'] };
|
|
500
|
+
const fields = required[action];
|
|
501
|
+
if (!fields || fields.some((key) => typeof body[key] !== 'string' || !textOf(body[key]).trim()) || Object.keys(body).some((key) => !fields.includes(key) && !(action === 'reject' && key === 'reason')) || action === 'reject' && body.reason !== undefined && typeof body.reason !== 'string' || action === 'bind' && !['owner', 'subject'].includes(textOf(body.role))) {
|
|
502
|
+
sendJson(res, 400, { ok: false, error_code: 'bad_request', error_message: 'Ownership 2.1 control parameters are invalid' });
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
let task;
|
|
507
|
+
switch (action) {
|
|
508
|
+
case 'bind':
|
|
509
|
+
task = body.role === 'owner' ? await this.client.bindSubaid(textOf(body.peer_aid)) : await this.client.bindOwneraid(textOf(body.peer_aid));
|
|
510
|
+
break;
|
|
511
|
+
case 'accept':
|
|
512
|
+
task = await this.client.acceptOwnershipRequest(textOf(body.operation_id));
|
|
513
|
+
break;
|
|
514
|
+
case 'reject':
|
|
515
|
+
task = await this.client.rejectOwnershipRequest(textOf(body.operation_id), body.reason);
|
|
516
|
+
break;
|
|
517
|
+
case 'release':
|
|
518
|
+
task = await this.client.releaseSubaid(textOf(body.sub_aid));
|
|
519
|
+
break;
|
|
520
|
+
default: task = await this.client.transferSubaid(textOf(body.sub_aid), textOf(body.new_owner_aid));
|
|
521
|
+
}
|
|
522
|
+
sendJson(res, 200, { ok: true, operation_id: task.operation_id, task: jsonSafe(task) });
|
|
523
|
+
}
|
|
524
|
+
catch (error) {
|
|
525
|
+
sendJson(res, 500, { ok: false, error_code: ownershipErrorCode(error), error_message: error instanceof Error ? error.message : String(error) });
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
async ownershipStatus(url, res) {
|
|
529
|
+
try {
|
|
530
|
+
const internal = this.client;
|
|
531
|
+
if (!internal._tokenStore?.listOwnershipTasks)
|
|
532
|
+
throw new StateError('ownership durable task storage is unavailable', { stringCode: 'persistence_unavailable' });
|
|
533
|
+
const operationId = textOf(url.searchParams.get('operation_id')).trim();
|
|
534
|
+
const requestedSub = textOf(url.searchParams.get('sub_aid')).trim();
|
|
535
|
+
const records = (await internal._tokenStore.listOwnershipTasks(this.aid))
|
|
536
|
+
.map((snapshot) => snapshot.record)
|
|
537
|
+
.filter((record) => (!operationId || record.operation_id === operationId) && (!requestedSub || record.sub_aid === requestedSub))
|
|
538
|
+
.sort((first, second) => second.created_at - first.created_at);
|
|
539
|
+
const publicTask = (record) => {
|
|
540
|
+
const localApproval = { pending: 'pending', accept: 'accepted', reject: 'rejected' }[record.local_decision];
|
|
541
|
+
if (!localApproval || typeof record.initiator_aid !== 'string' || !record.initiator_aid)
|
|
542
|
+
throw new StateError('ownership persisted approval is damaged', { stringCode: 'persistence_unavailable' });
|
|
543
|
+
return { ...ownershipTaskResult(record), initiator_aid: record.initiator_aid, local_approval: localApproval };
|
|
544
|
+
};
|
|
545
|
+
const tasks = records.map(publicTask), task = tasks[0] ?? null, record = records[0];
|
|
546
|
+
const subAid = record?.sub_aid || requestedSub || this.aid;
|
|
547
|
+
const consensus = await this.client.checkOwnershipConsensus(subAid);
|
|
548
|
+
const files = { agent_md: null, owner_md: null, storage_agent_md: null };
|
|
549
|
+
const fileErrors = {};
|
|
550
|
+
const evidence = (raw) => ({ raw_base64: Buffer.from(raw, 'utf-8').toString('base64'), sha256: crypto.createHash('sha256').update(raw, 'utf-8').digest('hex') });
|
|
551
|
+
const errorText = (error) => ownershipErrorCode(error) + ': ' + (error instanceof Error ? error.message : String(error));
|
|
552
|
+
let ns = null;
|
|
553
|
+
try {
|
|
554
|
+
if (!internal._agentMdManager)
|
|
555
|
+
throw new StateError('NS fresh reader is unavailable', { stringCode: 'unavailable' });
|
|
556
|
+
ns = await internal._agentMdManager.readOwnershipFresh(subAid);
|
|
557
|
+
if (ns.exists)
|
|
558
|
+
files.agent_md = evidence(ns.content);
|
|
559
|
+
else
|
|
560
|
+
fileErrors.agent_md = 'not_found';
|
|
561
|
+
}
|
|
562
|
+
catch (error) {
|
|
563
|
+
fileErrors.agent_md = errorText(error);
|
|
564
|
+
}
|
|
565
|
+
const storage = new OwnershipStorageAdapter({ currentAid: () => this.aid, call: (method, params) => this.client.call(method, params) });
|
|
566
|
+
const ownerAid = record ? record.operation === 'transfer' ? record.new_owner_aid : record.owner_aid : consensus.owner_aid;
|
|
567
|
+
if (ownerAid) {
|
|
568
|
+
try {
|
|
569
|
+
const owner = await storage.readOwnerMd(ownerAid, subAid);
|
|
570
|
+
if (owner.exists)
|
|
571
|
+
files.owner_md = evidence(owner.content);
|
|
572
|
+
else
|
|
573
|
+
fileErrors.owner_md = 'not_found';
|
|
574
|
+
}
|
|
575
|
+
catch (error) {
|
|
576
|
+
fileErrors.owner_md = errorText(error);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
else
|
|
580
|
+
fileErrors.owner_md = 'owner_unavailable';
|
|
581
|
+
try {
|
|
582
|
+
const copy = await storage.readFile(subAid, 'agent.md');
|
|
583
|
+
if (copy.exists)
|
|
584
|
+
files.storage_agent_md = evidence(copy.content);
|
|
585
|
+
else
|
|
586
|
+
fileErrors.storage_agent_md = 'not_found';
|
|
587
|
+
}
|
|
588
|
+
catch (error) {
|
|
589
|
+
fileErrors.storage_agent_md = errorText(error);
|
|
590
|
+
}
|
|
591
|
+
sendJson(res, 200, { ok: true, aid: this.aid, task: jsonSafe(task), tasks: jsonSafe(tasks), events: this.ownershipEvents, consensus: jsonSafe(consensus), ns_protocol: ns?.protocol ?? null, files, file_errors: fileErrors });
|
|
592
|
+
}
|
|
593
|
+
catch (error) {
|
|
594
|
+
sendJson(res, 500, { ok: false, error_code: ownershipErrorCode(error), error_message: error instanceof Error ? error.message : String(error) });
|
|
595
|
+
}
|
|
596
|
+
}
|
|
442
597
|
async handle(req, res) {
|
|
443
598
|
const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
|
|
444
599
|
try {
|
|
@@ -478,6 +633,7 @@ class CrossSdkJsAgent {
|
|
|
478
633
|
this.rawPushRpcMethods = [];
|
|
479
634
|
this.groupChangedEvents = [];
|
|
480
635
|
this.groupInviteEvents = [];
|
|
636
|
+
this.readStateEvents = [];
|
|
481
637
|
this.rawPushObservationId = textOf(body.observation_id ?? '');
|
|
482
638
|
sendJson(res, 200, { ok: true, observation_id: this.rawPushObservationId });
|
|
483
639
|
return;
|
|
@@ -516,6 +672,7 @@ class CrossSdkJsAgent {
|
|
|
516
672
|
rpc_calls: rpcEntries,
|
|
517
673
|
group_changed_events: groupChangedEvents.slice(-limit),
|
|
518
674
|
group_invite_events: groupInviteEvents.slice(-limit),
|
|
675
|
+
read_state_events: this.readStateEvents.slice(-limit),
|
|
519
676
|
});
|
|
520
677
|
return;
|
|
521
678
|
}
|
|
@@ -523,6 +680,22 @@ class CrossSdkJsAgent {
|
|
|
523
680
|
sendJson(res, 200, await this.identity());
|
|
524
681
|
return;
|
|
525
682
|
}
|
|
683
|
+
if (req.method === 'POST' && url.pathname === '/signature/call') {
|
|
684
|
+
await this.signatureCall(req, res);
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
if (req.method === 'POST' && ['/ownership/bind', '/ownership/accept', '/ownership/reject', '/ownership/release', '/ownership/transfer'].includes(url.pathname)) {
|
|
688
|
+
await this.ownershipControl(req, res, url.pathname.slice('/ownership/'.length));
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
if (req.method === 'GET' && url.pathname === '/ownership/status') {
|
|
692
|
+
await this.ownershipStatus(url, res);
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
if (req.method === 'GET' && url.pathname === '/ownership/events') {
|
|
696
|
+
sendJson(res, 200, { ok: true, events: this.ownershipEvents });
|
|
697
|
+
return;
|
|
698
|
+
}
|
|
526
699
|
if (req.method === 'POST' && url.pathname === '/send') {
|
|
527
700
|
await this.send(req, res);
|
|
528
701
|
return;
|
|
@@ -535,6 +708,10 @@ class CrossSdkJsAgent {
|
|
|
535
708
|
await this.pull(req, res);
|
|
536
709
|
return;
|
|
537
710
|
}
|
|
711
|
+
if (req.method === 'POST' && url.pathname === '/message/call') {
|
|
712
|
+
await this.messageCall(req, res);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
538
715
|
if (req.method === 'GET' && url.pathname === '/sync/state') {
|
|
539
716
|
this.syncState(url, res);
|
|
540
717
|
return;
|
|
@@ -655,6 +832,77 @@ class CrossSdkJsAgent {
|
|
|
655
832
|
});
|
|
656
833
|
}
|
|
657
834
|
}
|
|
835
|
+
async signatureCall(req, res) {
|
|
836
|
+
const body = await readJson(req);
|
|
837
|
+
const action = textOf(body.action), aid = textOf(body.aid || this.aid);
|
|
838
|
+
const store = this.aidStore();
|
|
839
|
+
let fileBytes;
|
|
840
|
+
let identity;
|
|
841
|
+
const output = (result) => {
|
|
842
|
+
const response = result.ok ? { ok: true, result: jsonSafe(result.data) } : { ok: false, error_code: result.error.code, error_message: result.error.message };
|
|
843
|
+
if (identity) {
|
|
844
|
+
response.certificate = identity.certPem;
|
|
845
|
+
response.cert_fingerprint = identity.certFingerprint;
|
|
846
|
+
}
|
|
847
|
+
if (fileBytes)
|
|
848
|
+
response.file_base64 = Buffer.from(fileBytes).toString('base64');
|
|
849
|
+
sendJson(res, 200, response);
|
|
850
|
+
};
|
|
851
|
+
try {
|
|
852
|
+
if (!['certificate', 'sign', 'verify', 'upload_agent_md', 'download_agent_md'].includes(action)) {
|
|
853
|
+
output({ ok: false, error: { code: 'unsupported_action', message: action } });
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
if (action === 'upload_agent_md') {
|
|
857
|
+
output(await store.uploadAgentMd(aid, textOf(body.input)));
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
if (action === 'download_agent_md') {
|
|
861
|
+
output(await store.downloadAgentMd(aid));
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
let input = textOf(body.input);
|
|
865
|
+
if (body.input_type === 'file') {
|
|
866
|
+
fileBytes = new Uint8Array(typeof body.input_base64 === 'string' ? Buffer.from(body.input_base64, 'base64') : Buffer.from(textOf(body.input), 'utf8'));
|
|
867
|
+
input = body.in_place === true ? {
|
|
868
|
+
getFile: async () => new Blob([new Uint8Array(fileBytes)]),
|
|
869
|
+
createWritable: async () => ({ write: async (content) => { fileBytes = new TextEncoder().encode(content); }, close: async () => { } }),
|
|
870
|
+
} : new Blob([new Uint8Array(fileBytes)]);
|
|
871
|
+
}
|
|
872
|
+
if (action !== 'verify') {
|
|
873
|
+
const loaded = await store.load(aid);
|
|
874
|
+
if (!loaded.ok) {
|
|
875
|
+
output(loaded);
|
|
876
|
+
return;
|
|
877
|
+
}
|
|
878
|
+
identity = loaded.data.aid;
|
|
879
|
+
if (action === 'certificate') {
|
|
880
|
+
output({ ok: true, data: { aid, certificate: identity.certPem, cert_fingerprint: identity.certFingerprint } });
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
const options = { identity, inputType: body.input_type, format: body.format, append: body.append, tag: body.tag, inPlace: body.in_place };
|
|
884
|
+
output(await store.sign(aid, input, options));
|
|
885
|
+
return;
|
|
886
|
+
}
|
|
887
|
+
const certificates = jsonObjectOf(body.certificates) ?? {};
|
|
888
|
+
const resolveCertificate = (signer) => {
|
|
889
|
+
const certificate = textOf(certificates[signer]);
|
|
890
|
+
if (!certificate)
|
|
891
|
+
throw new Error(`verification certificate missing for AID: ${signer}`);
|
|
892
|
+
return certificate;
|
|
893
|
+
};
|
|
894
|
+
if (body.format !== 'document' || certificates[aid])
|
|
895
|
+
identity = await AID.create({ aid, aunPath: this.aunPath, certPem: resolveCertificate(aid), privateKeyPem: null, certValid: true, privateKeyValid: false });
|
|
896
|
+
const options = { identity, inputType: body.input_type, format: body.format, certificateResolver: resolveCertificate };
|
|
897
|
+
output(await store.verify(aid, input, textOf(body.signature), options));
|
|
898
|
+
}
|
|
899
|
+
catch (error) {
|
|
900
|
+
output({ ok: false, error: { code: action === 'verify' ? 'VERIFICATION_OPERATION_ERROR' : 'SIGNATURE_OPERATION_ERROR', message: error instanceof Error ? error.message : String(error) } });
|
|
901
|
+
}
|
|
902
|
+
finally {
|
|
903
|
+
store.close();
|
|
904
|
+
}
|
|
905
|
+
}
|
|
658
906
|
async collabCall(req, res) {
|
|
659
907
|
const body = await readJson(req);
|
|
660
908
|
const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
|
|
@@ -678,6 +926,84 @@ class CrossSdkJsAgent {
|
|
|
678
926
|
sendJson(res, 500, error);
|
|
679
927
|
}
|
|
680
928
|
}
|
|
929
|
+
async orgProtocol(params) {
|
|
930
|
+
const op = textOf(params.op);
|
|
931
|
+
const now = Math.floor(Date.now() / 1000);
|
|
932
|
+
if (op === 'request')
|
|
933
|
+
return buildRequestBinding(textOf(params.method), textOf(params.target), params.params, textOf(params.credential_cid), textOf(params.nonce), textOf(params.request_id), now, now + 300);
|
|
934
|
+
if (['register', 'sign', 'certificate', 'create', 'prepare'].includes(op)) {
|
|
935
|
+
const store = this.aidStore();
|
|
936
|
+
try {
|
|
937
|
+
if (op === 'prepare') {
|
|
938
|
+
const request = jsonObjectOf(params.params) ?? {};
|
|
939
|
+
const orgId = textOf(params.org_id ?? request.org_id);
|
|
940
|
+
const loaded = orgId ? await store.load(orgId) : null;
|
|
941
|
+
const orgSigner = loaded?.ok && loaded.data.aid.isPrivateKeyValid() ? loaded.data.aid : undefined;
|
|
942
|
+
return await this.client.org.prepareRequest(textOf(params.method), request, textOf(params.target), this.client.currentAid, { ...jsonObjectOf(params.options), orgSigner });
|
|
943
|
+
}
|
|
944
|
+
if (op === 'register') {
|
|
945
|
+
const registered = await store.register(textOf(params.org_id), { type: 'org', owner: this.aid, exttype: 'company' });
|
|
946
|
+
if (!registered.ok)
|
|
947
|
+
throw new Error(String(registered.error));
|
|
948
|
+
}
|
|
949
|
+
const loaded = op === 'certificate'
|
|
950
|
+
? await store.resolve(textOf(params.as_aid), { skipAgentMd: true })
|
|
951
|
+
: (params.as_aid || params.org_id) ? await store.load(textOf(params.as_aid ?? params.org_id)) : null;
|
|
952
|
+
if (loaded && !loaded.ok)
|
|
953
|
+
throw new Error(String(loaded.error));
|
|
954
|
+
const identity = loaded?.data?.aid ?? this.client.currentAid;
|
|
955
|
+
const result = { cert_fingerprint: identity.certFingerprint, certificate: identity.certPem };
|
|
956
|
+
if (op === 'sign') {
|
|
957
|
+
const signed = await identity.sign(canonicalJson(params.payload));
|
|
958
|
+
if (!signed.ok)
|
|
959
|
+
throw new Error(String(signed.error));
|
|
960
|
+
result.signature = { cert_fingerprint: identity.certFingerprint, timestamp: now, signature: signed.data.signature };
|
|
961
|
+
}
|
|
962
|
+
else if (op === 'create') {
|
|
963
|
+
result.credential = params.membership_binding
|
|
964
|
+
? await this.client.org.member.createCredential(params.membership_binding, identity, params.options)
|
|
965
|
+
: await this.client.credential.create(params.options, identity);
|
|
966
|
+
}
|
|
967
|
+
return result;
|
|
968
|
+
}
|
|
969
|
+
finally {
|
|
970
|
+
store.close();
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
const value = params.document ?? params.payload;
|
|
974
|
+
const result = { canonical: new TextDecoder().decode(canonicalJson(value)), digest: digest(value), error_code: '' };
|
|
975
|
+
if (op === 'verify' || op === 'verify_full') {
|
|
976
|
+
const verificationNow = typeof params.now === 'number' ? params.now : now;
|
|
977
|
+
const certificates = params.certificates;
|
|
978
|
+
const resolver = (fingerprint) => certificates[fingerprint];
|
|
979
|
+
try {
|
|
980
|
+
if (op === 'verify_full') {
|
|
981
|
+
const actual = jsonObjectOf(params.context) ?? params;
|
|
982
|
+
const memberships = jsonObjectOf(params.memberships) ?? {};
|
|
983
|
+
result.verification = { ...await this.client.credential.verify(value, { resolveCertificate: resolver, resolveActorCertificate: resolver,
|
|
984
|
+
resolveStatus: (cid) => params.statuses?.[cid], now: verificationNow, audience: textOf(actual.audience), subject: textOf(actual.subject) || undefined,
|
|
985
|
+
ns: textOf(actual.ns), action: textOf(actual.action), resource: textOf(actual.resource), rootIssuer: textOf(actual.root_issuer) || undefined,
|
|
986
|
+
params: jsonObjectOf(actual.params) ?? {}, units: jsonObjectOf(actual.units) ?? {}, clientIp: textOf(actual.client_ip), method: textOf(actual.method), target: textOf(actual.target),
|
|
987
|
+
requestId: textOf(actual.request_id), nonce: textOf(actual.nonce), requestBinding: actual.request_binding, proofChain: actual.proof_chain, membershipBinding: actual.membership_binding,
|
|
988
|
+
orgSigner: textOf(actual.org_signer) || undefined, actor: textOf(actual.actor) || undefined, for: textOf(actual.for) || undefined, representationProof: actual.representation_proof,
|
|
989
|
+
resolveMembershipStatus: (binding, credential) => { const current = jsonObjectOf(memberships[String(binding.membership_id)]); return current?.status === 'active' && current.credential_cid === credential.cid; },
|
|
990
|
+
resolveOwnership: (subject, owner) => (jsonObjectOf(params.ownerships) ?? {})[subject] === owner, checkRateLimit: () => params.rate_limit_allowed === true }) };
|
|
991
|
+
}
|
|
992
|
+
else if (params.kind === 'credential')
|
|
993
|
+
result.verification = { ...await this.client.credential.verifySignature(value, resolver, verificationNow, textOf(params.audience)) };
|
|
994
|
+
else if (params.kind === 'binding')
|
|
995
|
+
await verifyMembershipBinding(value, resolver, verificationNow, textOf(params.expected_org_signer));
|
|
996
|
+
else
|
|
997
|
+
result.verification = { ...await this.client.credential.verifyRegistrationReceipt(value, params.credential, params.request, resolver, textOf(params.service_aid), verificationNow) };
|
|
998
|
+
}
|
|
999
|
+
catch (error) {
|
|
1000
|
+
if (!(error instanceof ProtocolError))
|
|
1001
|
+
throw error;
|
|
1002
|
+
result.error_code = error.code;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
return result;
|
|
1006
|
+
}
|
|
681
1007
|
async groupCall(req, res) {
|
|
682
1008
|
const body = await readJson(req);
|
|
683
1009
|
const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
|
|
@@ -693,6 +1019,48 @@ class CrossSdkJsAgent {
|
|
|
693
1019
|
try {
|
|
694
1020
|
let result;
|
|
695
1021
|
switch (method) {
|
|
1022
|
+
case 'sdk.org.protocol':
|
|
1023
|
+
result = await this.orgProtocol(params);
|
|
1024
|
+
break;
|
|
1025
|
+
case 'org.lifecycle.create':
|
|
1026
|
+
result = await this.client.org.lifecycle.create(params);
|
|
1027
|
+
break;
|
|
1028
|
+
case 'org.lifecycle.dissolve':
|
|
1029
|
+
result = await this.client.org.lifecycle.dissolve(params);
|
|
1030
|
+
break;
|
|
1031
|
+
case 'org.lifecycle.transfer':
|
|
1032
|
+
result = await this.client.org.lifecycle.transfer(params);
|
|
1033
|
+
break;
|
|
1034
|
+
case 'org.lifecycle.transferAccept':
|
|
1035
|
+
result = await this.client.org.lifecycle.transferAccept(params);
|
|
1036
|
+
break;
|
|
1037
|
+
case 'org.member.join':
|
|
1038
|
+
result = await this.client.org.member.join(params);
|
|
1039
|
+
break;
|
|
1040
|
+
case 'org.member.approveJoin':
|
|
1041
|
+
result = await this.client.org.member.approveJoin(params);
|
|
1042
|
+
break;
|
|
1043
|
+
case 'org.member.rejectJoin':
|
|
1044
|
+
result = await this.client.org.member.rejectJoin(params);
|
|
1045
|
+
break;
|
|
1046
|
+
case 'org.member.invite':
|
|
1047
|
+
result = await this.client.org.member.invite(params);
|
|
1048
|
+
break;
|
|
1049
|
+
case 'org.member.inviteAccept':
|
|
1050
|
+
result = await this.client.org.member.inviteAccept(params);
|
|
1051
|
+
break;
|
|
1052
|
+
case 'org.member.inviteReject':
|
|
1053
|
+
result = await this.client.org.member.inviteReject(params);
|
|
1054
|
+
break;
|
|
1055
|
+
case 'org.member.leave':
|
|
1056
|
+
result = await this.client.org.member.leave(params);
|
|
1057
|
+
break;
|
|
1058
|
+
case 'org.member.offboard':
|
|
1059
|
+
result = await this.client.org.member.offboard(params);
|
|
1060
|
+
break;
|
|
1061
|
+
case 'org.credential.getStatus':
|
|
1062
|
+
result = await this.client.org.credential.getStatus(params);
|
|
1063
|
+
break;
|
|
696
1064
|
case 'sdk.update_group_index':
|
|
697
1065
|
result = await this.client.group.updateGroupIndex(params);
|
|
698
1066
|
break;
|
|
@@ -726,6 +1094,12 @@ class CrossSdkJsAgent {
|
|
|
726
1094
|
case 'group.get_member_statuses':
|
|
727
1095
|
result = await this.client.group.getMemberStatuses(params);
|
|
728
1096
|
break;
|
|
1097
|
+
case 'group.read':
|
|
1098
|
+
result = await this.client.group.read(params);
|
|
1099
|
+
break;
|
|
1100
|
+
case 'group.read_state':
|
|
1101
|
+
result = await this.client.group.readState(params);
|
|
1102
|
+
break;
|
|
729
1103
|
default: result = await this.client.call(method, params);
|
|
730
1104
|
}
|
|
731
1105
|
const response = { ok: true, trace_id: traceId, method, result: jsonSafe(result) };
|
|
@@ -1395,6 +1769,39 @@ class CrossSdkJsAgent {
|
|
|
1395
1769
|
});
|
|
1396
1770
|
}
|
|
1397
1771
|
}
|
|
1772
|
+
async messageCall(req, res) {
|
|
1773
|
+
const body = await readJson(req);
|
|
1774
|
+
const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
|
|
1775
|
+
const method = textOf(body.method).trim();
|
|
1776
|
+
const params = jsonObjectOf(body.params) ?? {};
|
|
1777
|
+
if (!method) {
|
|
1778
|
+
sendJson(res, 400, { ok: false, trace_id: traceId, error_code: 'bad_request', error_message: 'method is required' });
|
|
1779
|
+
return;
|
|
1780
|
+
}
|
|
1781
|
+
try {
|
|
1782
|
+
let result;
|
|
1783
|
+
if (method === 'message.read')
|
|
1784
|
+
result = await this.client.message.read(params);
|
|
1785
|
+
else if (method === 'message.read_state')
|
|
1786
|
+
result = await this.client.message.readState(params);
|
|
1787
|
+
else
|
|
1788
|
+
result = await this.client.call(method, params);
|
|
1789
|
+
const response = { ok: true, trace_id: traceId, method, result: jsonSafe(result) };
|
|
1790
|
+
this.recordTrace(traceId, { stage: 'message_call', method, result: response });
|
|
1791
|
+
sendJson(res, 200, response);
|
|
1792
|
+
}
|
|
1793
|
+
catch (err) {
|
|
1794
|
+
const error = {
|
|
1795
|
+
ok: false,
|
|
1796
|
+
trace_id: traceId,
|
|
1797
|
+
method,
|
|
1798
|
+
error_code: err instanceof Error ? err.name : 'Error',
|
|
1799
|
+
error_message: err instanceof Error ? err.message : String(err),
|
|
1800
|
+
};
|
|
1801
|
+
this.recordTrace(traceId, { stage: 'message_call_error', method, error });
|
|
1802
|
+
sendJson(res, 500, error);
|
|
1803
|
+
}
|
|
1804
|
+
}
|
|
1398
1805
|
syncNamespace(scope, groupId = '') {
|
|
1399
1806
|
if (scope === 'p2p')
|
|
1400
1807
|
return `p2p:${this.aid}`;
|
|
@@ -1831,5 +2238,6 @@ async function main() {
|
|
|
1831
2238
|
process.on('SIGINT', () => { void shutdown(); });
|
|
1832
2239
|
process.on('SIGTERM', () => { void shutdown(); });
|
|
1833
2240
|
}
|
|
1834
|
-
|
|
2241
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url))
|
|
2242
|
+
void main();
|
|
1835
2243
|
//# sourceMappingURL=cross-sdk-agent.js.map
|