@agentunion/fastaun 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.
Files changed (122) hide show
  1. package/CHANGELOG.md +172 -79
  2. package/_packed_docs/CHANGELOG.md +172 -79
  3. package/_packed_docs/INDEX.md +244 -116
  4. package/_packed_docs/KITE_DOCS_GUIDE.md +98 -69
  5. package/_packed_docs/agent.md/SCHEMA.md +245 -205
  6. 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
  7. 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
  8. 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
  9. 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
  10. package/_packed_docs/protocol/06-/346/234/215/345/212/241/345/215/217/350/256/256.md +1072 -1072
  11. 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
  12. package/_packed_docs/protocol/10-Group-/345/255/220/345/215/217/350/256/256.md +687 -668
  13. package/_packed_docs/protocol/11-Storage-/345/255/220/345/215/217/350/256/256.md +19 -28
  14. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/211.md +443 -0
  15. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.0.md +161 -0
  16. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2112.1.md +658 -0
  17. package/_packed_docs/protocol/Ownership/345/215/217/350/256/256/345/256/232/344/271/2113.0.md +233 -0
  18. package/_packed_docs/protocol/agent.md/SCHEMA.md +4 -0
  19. package/_packed_docs/sdk/03-/346/240/270/345/277/203/346/246/202/345/277/265.md +1 -1
  20. package/_packed_docs/sdk/04-/350/277/236/346/216/245/344/270/216/350/256/244/350/257/201.md +68 -61
  21. package/_packed_docs/sdk/05-E2EE/345/212/240/345/257/206/351/200/232/344/277/241.md +1 -1
  22. package/_packed_docs/sdk/06-API/346/211/213/345/206/214.md +279 -285
  23. package/_packed_docs/sdk/08-/346/234/200/344/275/263/345/256/236/350/267/265.md +3 -3
  24. package/_packed_docs/sdk/09-group-rpc-manual.md +271 -235
  25. package/_packed_docs/sdk/09-message-rpc-manual.md +47 -6
  26. package/_packed_docs/sdk/09-storage-rpc-manual.md +70 -68
  27. package/_packed_docs/sdk/AUN_DOCS_GUIDE.md +63 -34
  28. package/_packed_docs/sdk/INDEX.md +105 -34
  29. package/_packed_docs/sdk/Ownership-SDK/345/256/236/347/216/260/346/214/207/345/215/227.md +169 -0
  30. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/227.md +349 -0
  31. package/_packed_docs/sdk/Ownership-SDK/347/274/226/346/216/222/346/214/207/345/215/2272.1.md +922 -0
  32. package/_packed_docs/sdk/Ownership-SDK/351/233/206/346/210/220/346/214/207/345/215/227.md +270 -0
  33. 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
  34. 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
  35. 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
  36. package/_packed_docs/sdk/Ownership2.1/350/257/246/347/273/206/350/256/276/350/256/241.md +476 -0
  37. package/_packed_docs/sdk/Ownership/347/256/241/347/220/206/344/270/223/351/242/230.md +559 -0
  38. package/_packed_docs/sdk/ProtectedHeaders/347/224/250/346/263/225/344/270/223/351/242/230.md +299 -0
  39. 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
  40. 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
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. package/dist/agent-md-schema.d.ts +15 -1
  48. package/dist/agent-md-schema.js +87 -24
  49. package/dist/agent-md-schema.js.map +1 -1
  50. package/dist/agent-md.d.ts +54 -2
  51. package/dist/agent-md.js +637 -53
  52. package/dist/agent-md.js.map +1 -1
  53. package/dist/aid-store.d.ts +38 -59
  54. package/dist/aid-store.js +300 -265
  55. package/dist/aid-store.js.map +1 -1
  56. package/dist/aid.js +30 -11
  57. package/dist/aid.js.map +1 -1
  58. package/dist/auth.d.ts +6 -1
  59. package/dist/auth.js +500 -15
  60. package/dist/auth.js.map +1 -1
  61. package/dist/cert-utils.d.ts +44 -2
  62. package/dist/cert-utils.js +149 -49
  63. package/dist/cert-utils.js.map +1 -1
  64. package/dist/client/delivery.d.ts +11 -1
  65. package/dist/client/delivery.js +321 -62
  66. package/dist/client/delivery.js.map +1 -1
  67. package/dist/client/rpc-pipeline.d.ts +1 -0
  68. package/dist/client/rpc-pipeline.js +142 -82
  69. package/dist/client/rpc-pipeline.js.map +1 -1
  70. package/dist/client/v2-e2ee.d.ts +1 -0
  71. package/dist/client/v2-e2ee.js +166 -96
  72. package/dist/client/v2-e2ee.js.map +1 -1
  73. package/dist/client.d.ts +84 -1
  74. package/dist/client.js +780 -30
  75. package/dist/client.js.map +1 -1
  76. package/dist/errors.js +4 -3
  77. package/dist/errors.js.map +1 -1
  78. package/dist/events.d.ts +9 -3
  79. package/dist/events.js +69 -11
  80. package/dist/events.js.map +1 -1
  81. package/dist/facades.d.ts +83 -3
  82. package/dist/facades.js +100 -6
  83. package/dist/facades.js.map +1 -1
  84. package/dist/index.d.ts +9 -4
  85. package/dist/index.js +3 -2
  86. package/dist/index.js.map +1 -1
  87. package/dist/keystore/aid-db.d.ts +5 -0
  88. package/dist/keystore/aid-db.js +57 -0
  89. package/dist/keystore/aid-db.js.map +1 -1
  90. package/dist/keystore/index.d.ts +8 -0
  91. package/dist/keystore/local-identity-store.js +10 -3
  92. package/dist/keystore/local-identity-store.js.map +1 -1
  93. package/dist/keystore/local-token-store.d.ts +6 -1
  94. package/dist/keystore/local-token-store.js +24 -1
  95. package/dist/keystore/local-token-store.js.map +1 -1
  96. package/dist/org-protocol.d.ts +98 -0
  97. package/dist/org-protocol.js +1753 -0
  98. package/dist/org-protocol.js.map +1 -0
  99. package/dist/ownership-proof.d.ts +82 -5
  100. package/dist/ownership-proof.js +327 -31
  101. package/dist/ownership-proof.js.map +1 -1
  102. package/dist/ownership-v21.d.ts +196 -0
  103. package/dist/ownership-v21.js +712 -0
  104. package/dist/ownership-v21.js.map +1 -0
  105. package/dist/ownership-workflow.d.ts +87 -0
  106. package/dist/ownership-workflow.js +1182 -0
  107. package/dist/ownership-workflow.js.map +1 -0
  108. package/dist/seq-tracker.d.ts +1 -0
  109. package/dist/seq-tracker.js +10 -1
  110. package/dist/seq-tracker.js.map +1 -1
  111. package/dist/tools/cross-sdk-agent.d.ts +90 -1
  112. package/dist/tools/cross-sdk-agent.js +441 -7
  113. package/dist/tools/cross-sdk-agent.js.map +1 -1
  114. package/dist/transport.d.ts +8 -0
  115. package/dist/transport.js +118 -4
  116. package/dist/transport.js.map +1 -1
  117. package/dist/v2/e2ee/decrypt.d.ts +1 -0
  118. package/dist/v2/e2ee/decrypt.js +9 -1
  119. package/dist/v2/e2ee/decrypt.js.map +1 -1
  120. package/dist/version.d.ts +1 -1
  121. package/dist/version.js +1 -1
  122. package/package.json +1 -1
@@ -3,11 +3,17 @@ 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';
7
+ import { tmpdir } from 'node:os';
6
8
  import { URL } from 'node:url';
9
+ import { fileURLToPath } from 'node:url';
7
10
  import { AUNClient } from '../client.js';
11
+ import { AID } from '../aid.js';
8
12
  import { AIDStore } from '../aid-store.js';
9
13
  import { publicKeyFingerprint } from '../cert-utils.js';
10
14
  import { VERSION } from '../version.js';
15
+ import { canonicalJson, digest, buildRequestBinding, verifyMembershipBinding, ProtocolError } from '../org-protocol.js';
16
+ import { ownershipTaskResult } from '../ownership-workflow.js';
11
17
  function envBool(name, fallback = false) {
12
18
  const raw = process.env[name];
13
19
  if (raw == null)
@@ -105,7 +111,7 @@ function sendJson(res, status, data) {
105
111
  });
106
112
  res.end(body);
107
113
  }
108
- class CrossSdkTsAgent {
114
+ export class CrossSdkTsAgent {
109
115
  language = 'ts';
110
116
  sdkVersion = VERSION;
111
117
  aid = textOf(process.env.AUN_TEST_AID || 'cross-ts.agentid.pub').trim();
@@ -125,6 +131,8 @@ class CrossSdkTsAgent {
125
131
  rpcObservedTransports = new WeakSet();
126
132
  groupChangedEvents = [];
127
133
  groupInviteEvents = [];
134
+ readStateEvents = [];
135
+ ownershipEvents = [];
128
136
  traces = new Map();
129
137
  sendResults = new Map();
130
138
  inlineRealtimePayloadV1 = true;
@@ -166,6 +174,21 @@ class CrossSdkTsAgent {
166
174
  });
167
175
  this.client.on('group.changed', (data) => this.storeGroupChangedPublicEvent(data));
168
176
  this.client.on('group.invite_received', (data) => this.storeGroupInviteEvent(data));
177
+ for (const event of ['message.read_changed', 'group.read_changed', 'read_state_sync']) {
178
+ this.client.on(event, (payload) => { this.readStateEvents.push({ event, payload: jsonSafe(payload) }); });
179
+ }
180
+ for (const event of ['ownership.request', 'ownership.pending', 'ownership.progress', 'ownership.completed', 'ownership.rejected', 'ownership.stopped', 'ownership.error', 'ownership.action_required']) {
181
+ this.client.on(event, (payload) => {
182
+ this.ownershipEvents.push({ event, payload: jsonSafe(payload) });
183
+ });
184
+ }
185
+ for (const suffix of ['join_requested', 'join_approved', 'join_rejected', 'invite_created', 'invite_accepted', 'invite_rejected']) {
186
+ const event = 'org.member.' + suffix;
187
+ this.client.on(event, (value) => {
188
+ const payload = value;
189
+ this.recordTrace(textOf(payload.org_id), { stage: event, payload });
190
+ });
191
+ }
169
192
  }
170
193
  installTransportRpcObserver() {
171
194
  const transport = this.client._transport;
@@ -292,7 +315,14 @@ class CrossSdkTsAgent {
292
315
  debug: this.debug,
293
316
  });
294
317
  try {
295
- const registered = await store.register(this.aid);
318
+ const fixedIdentityFile = textOf(process.env.AUN_TEST_FIXED_IDENTITY_FILE).trim();
319
+ if (fixedIdentityFile) {
320
+ const identity = JSON.parse(fs.readFileSync(fixedIdentityFile, 'utf-8'));
321
+ if (identity.aid !== this.aid)
322
+ throw new Error('固定测试身份与配置 AID 不一致');
323
+ store._keystore.saveIdentity(this.aid, identity);
324
+ }
325
+ const registered = fixedIdentityFile ? store.load(this.aid) : await store.register(this.aid, { type: 'service' });
296
326
  if (!registered.ok) {
297
327
  const loaded = store.load(this.aid);
298
328
  if (!loaded.ok) {
@@ -301,6 +331,8 @@ class CrossSdkTsAgent {
301
331
  }
302
332
  }
303
333
  catch (err) {
334
+ if (textOf(process.env.AUN_TEST_FIXED_IDENTITY_FILE).trim())
335
+ throw err;
304
336
  const localIdentity = internal._auth?.loadIdentityOrNone?.(this.aid);
305
337
  if (!localIdentity) {
306
338
  throw new Error(`registerAid failed and no local identity exists: ${err instanceof Error ? err.message : String(err)}`);
@@ -310,11 +342,15 @@ class CrossSdkTsAgent {
310
342
  if (!loaded.ok) {
311
343
  throw new Error(`load identity failed: ${loaded.error.code}: ${loaded.error.message}`);
312
344
  }
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
345
  this.client.loadIdentity(loaded.data.aid);
346
+ const checked = await store.checkAgentMd(this.aid);
347
+ const localEtag = checked.ok ? String(checked.data.local_etag ?? '').trim() : '';
348
+ const remoteEtag = checked.ok ? String(checked.data.remote_etag ?? '').trim() : '';
349
+ const inSync = Boolean(localEtag && remoteEtag && localEtag === remoteEtag);
350
+ const remoteFound = checked.ok && checked.data.remote_found === true;
351
+ if (!inSync && !remoteFound) {
352
+ await this.client._ensureInitialAgentMd();
353
+ }
318
354
  this.installTransportRpcObserver();
319
355
  await this.client.connect({ auto_reconnect: false, background_sync: backgroundSync });
320
356
  }
@@ -330,6 +366,96 @@ class CrossSdkTsAgent {
330
366
  public_key_fingerprint: cert ? publicKeyFingerprint(cert) : '',
331
367
  };
332
368
  }
369
+ async ownershipBind(req, res) {
370
+ const body = await readJson(req);
371
+ const role = textOf(body.role).trim().toLowerCase();
372
+ const peerAid = textOf(body.peer_aid).trim();
373
+ if (!['owner', 'subject'].includes(role) || !peerAid) {
374
+ sendJson(res, 400, { ok: false, error_code: 'bad_request', error_message: 'role and peer_aid are required' });
375
+ return;
376
+ }
377
+ try {
378
+ const task = role === 'owner' ? await this.client.bindSubaid(peerAid) : await this.client.bindOwneraid(peerAid);
379
+ sendJson(res, 200, { ok: true, operation_id: task.operation_id, task: jsonSafe(task) });
380
+ }
381
+ catch (err) {
382
+ sendJson(res, 500, {
383
+ ok: false,
384
+ error_code: textOf(err?.stringCode ?? err?.code ?? (err instanceof Error ? err.name : 'Error')),
385
+ error_message: err instanceof Error ? err.message : String(err),
386
+ });
387
+ }
388
+ }
389
+ async ownershipAction(req, res, action) {
390
+ const body = await readJson(req);
391
+ const operationId = textOf(body.operation_id).trim(), subAid = textOf(body.sub_aid).trim(), newOwnerAid = textOf(body.new_owner_aid).trim();
392
+ if ((action === 'accept' || action === 'reject') ? !operationId : !subAid || action === 'transfer' && !newOwnerAid) {
393
+ 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' });
394
+ return;
395
+ }
396
+ try {
397
+ const task = action === 'accept' ? await this.client.acceptOwnershipRequest(operationId)
398
+ : action === 'reject' ? await this.client.rejectOwnershipRequest(operationId, body.reason)
399
+ : action === 'release' ? await this.client.releaseSubaid(subAid)
400
+ : await this.client.transferSubaid(subAid, newOwnerAid);
401
+ sendJson(res, 200, { ok: true, operation_id: task.operation_id, task: jsonSafe(task) });
402
+ }
403
+ catch (err) {
404
+ sendJson(res, 500, {
405
+ ok: false,
406
+ error_code: textOf(err?.stringCode ?? err?.code ?? (err instanceof Error ? err.name : 'Error')),
407
+ error_message: err instanceof Error ? err.message : String(err),
408
+ });
409
+ }
410
+ }
411
+ ownershipPublicTask(record) {
412
+ const decision = record.local_decision;
413
+ if (!['pending', 'accept', 'reject'].includes(String(decision)) || typeof record.initiator_aid !== 'string' || !record.initiator_aid)
414
+ throw new Error('persisted ownership approval context is unavailable');
415
+ return { ...ownershipTaskResult(record), initiator_aid: record.initiator_aid, local_approval: decision === 'accept' ? 'accepted' : decision === 'reject' ? 'rejected' : 'pending' };
416
+ }
417
+ async ownershipStatus(url, res) {
418
+ const internal = this.client;
419
+ if (!internal._tokenStore.listOwnershipTasks)
420
+ throw new Error('ownership task store is unavailable');
421
+ const operationId = textOf(url.searchParams.get('operation_id')).trim(), selectedSub = textOf(url.searchParams.get('sub_aid')).trim();
422
+ const records = internal._tokenStore.listOwnershipTasks(this.aid).map((item) => item.task).filter((record) => (!operationId || record.operation_id === operationId) && (!selectedSub || record.sub_aid === selectedSub));
423
+ const tasks = records.map((record) => this.ownershipPublicTask(record)), task = tasks[tasks.length - 1] ?? null;
424
+ const subAid = textOf(task?.sub_aid ?? selectedSub).trim() || this.aid;
425
+ const consensus = await this.client.checkOwnershipConsensus(subAid);
426
+ const files = { agent_md: null, owner_md: null, storage_agent_md: null }, fileErrors = {};
427
+ let nsProtocol = null;
428
+ try {
429
+ const current = await internal._getOwnershipFiles().readAgent(subAid);
430
+ nsProtocol = current.protocol;
431
+ if (!current.exists)
432
+ fileErrors.agent_md = 'not_found';
433
+ else
434
+ 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 };
435
+ }
436
+ catch (err) {
437
+ fileErrors.agent_md = err instanceof Error ? err.message : String(err);
438
+ }
439
+ const ownerAid = textOf(task?.operation === 'release' ? task.owner_aid : consensus.owner_aid ?? task?.new_owner_aid ?? task?.owner_aid).trim();
440
+ const readStorageFile = async (name, read) => {
441
+ try {
442
+ const current = await read();
443
+ if (!current.exists)
444
+ fileErrors[name] = 'not_found';
445
+ else
446
+ files[name] = { raw_base64: Buffer.from(current.content, 'utf8').toString('base64'), sha256: crypto.createHash('sha256').update(current.content, 'utf8').digest('hex') };
447
+ }
448
+ catch (err) {
449
+ fileErrors[name] = err instanceof Error ? err.message : String(err);
450
+ }
451
+ };
452
+ await Promise.all([
453
+ ownerAid ? readStorageFile('owner_md', () => internal._getOwnershipFiles().readOwner(ownerAid, subAid)) : Promise.resolve().then(() => { fileErrors.owner_md = 'owner_aid is unavailable'; }),
454
+ readStorageFile('storage_agent_md', () => internal._getOwnershipStorage().readObject(subAid, 'agent.md')),
455
+ ]);
456
+ const events = this.ownershipEvents.filter((item) => (!operationId || item.payload?.operation_id === operationId) && (!selectedSub || item.payload?.sub_aid === selectedSub));
457
+ sendJson(res, 200, { ok: true, task, tasks, events, consensus: consensus, files, file_errors: fileErrors, ns_protocol: nsProtocol });
458
+ }
333
459
  recordTrace(traceId, item) {
334
460
  if (!traceId)
335
461
  return;
@@ -439,6 +565,7 @@ class CrossSdkTsAgent {
439
565
  this.rawPushRpcMethods = [];
440
566
  this.groupChangedEvents = [];
441
567
  this.groupInviteEvents = [];
568
+ this.readStateEvents = [];
442
569
  this.rawPushObservationId = textOf(body.observation_id ?? '');
443
570
  sendJson(res, 200, { ok: true, observation_id: this.rawPushObservationId });
444
571
  return;
@@ -477,6 +604,7 @@ class CrossSdkTsAgent {
477
604
  rpc_calls: rpcEntries,
478
605
  group_changed_events: groupChangedEvents.slice(-limit),
479
606
  group_invite_events: groupInviteEvents.slice(-limit),
607
+ read_state_events: this.readStateEvents.slice(-limit),
480
608
  });
481
609
  return;
482
610
  }
@@ -484,6 +612,38 @@ class CrossSdkTsAgent {
484
612
  sendJson(res, 200, this.identity());
485
613
  return;
486
614
  }
615
+ if (req.method === 'POST' && url.pathname === '/signature/call') {
616
+ await this.signatureCall(req, res);
617
+ return;
618
+ }
619
+ if (req.method === 'POST' && url.pathname === '/ownership/bind') {
620
+ await this.ownershipBind(req, res);
621
+ return;
622
+ }
623
+ if (req.method === 'POST' && url.pathname === '/ownership/accept') {
624
+ await this.ownershipAction(req, res, 'accept');
625
+ return;
626
+ }
627
+ if (req.method === 'POST' && url.pathname === '/ownership/reject') {
628
+ await this.ownershipAction(req, res, 'reject');
629
+ return;
630
+ }
631
+ if (req.method === 'POST' && url.pathname === '/ownership/release') {
632
+ await this.ownershipAction(req, res, 'release');
633
+ return;
634
+ }
635
+ if (req.method === 'POST' && url.pathname === '/ownership/transfer') {
636
+ await this.ownershipAction(req, res, 'transfer');
637
+ return;
638
+ }
639
+ if (req.method === 'GET' && url.pathname === '/ownership/status') {
640
+ await this.ownershipStatus(url, res);
641
+ return;
642
+ }
643
+ if (req.method === 'GET' && url.pathname === '/ownership/events') {
644
+ sendJson(res, 200, { ok: true, events: this.ownershipEvents });
645
+ return;
646
+ }
487
647
  if (req.method === 'POST' && url.pathname === '/send') {
488
648
  await this.send(req, res);
489
649
  return;
@@ -496,6 +656,10 @@ class CrossSdkTsAgent {
496
656
  await this.pull(req, res);
497
657
  return;
498
658
  }
659
+ if (req.method === 'POST' && url.pathname === '/message/call') {
660
+ await this.messageCall(req, res);
661
+ return;
662
+ }
499
663
  if (req.method === 'GET' && url.pathname === '/sync/state') {
500
664
  this.syncState(url, res);
501
665
  return;
@@ -618,6 +782,95 @@ class CrossSdkTsAgent {
618
782
  });
619
783
  }
620
784
  }
785
+ async signatureCall(req, res) {
786
+ const body = await readJson(req);
787
+ const action = textOf(body.action);
788
+ const target = textOf(body.aid ?? this.aid);
789
+ const store = this.aidStore();
790
+ let directory = '', file = '';
791
+ try {
792
+ if (action === 'upload_agent_md' || action === 'download_agent_md') {
793
+ const operation = action === 'upload_agent_md'
794
+ ? await store.uploadAgentMd(target, textOf(body.input))
795
+ : await store.downloadAgentMd(target);
796
+ sendJson(res, 200, operation.ok
797
+ ? { ok: true, result: jsonSafe(operation.data) }
798
+ : { ok: false, error_code: operation.error.code, error_message: operation.error.message });
799
+ return;
800
+ }
801
+ if (action === 'certificate') {
802
+ const loaded = store.load(target);
803
+ if (!loaded.ok) {
804
+ sendJson(res, 200, { ok: false, error_code: loaded.error.code, error_message: loaded.error.message });
805
+ return;
806
+ }
807
+ const identity = loaded.data.aid;
808
+ const result = { aid: target, certificate: identity.certPem, cert_fingerprint: identity.certFingerprint };
809
+ sendJson(res, 200, { ok: true, result, certificate: identity.certPem, cert_fingerprint: identity.certFingerprint });
810
+ return;
811
+ }
812
+ if (action !== 'sign' && action !== 'verify') {
813
+ sendJson(res, 200, { ok: false, error_code: 'bad_request', error_message: `unsupported signature action: ${action}` });
814
+ return;
815
+ }
816
+ const options = {
817
+ inputType: (body.input_type ?? 'text'),
818
+ format: (body.format ?? 'raw'),
819
+ append: body.append === true,
820
+ tag: body.tag == null ? undefined : textOf(body.tag),
821
+ inPlace: body.in_place === true,
822
+ };
823
+ let input = textOf(body.input);
824
+ if (options.inputType === 'file') {
825
+ directory = fs.mkdtempSync(path.join(tmpdir(), 'aun-cross-signature-'));
826
+ file = path.join(directory, 'input');
827
+ fs.writeFileSync(file, body.input_base64 == null ? Buffer.from(input, 'utf8') : Buffer.from(textOf(body.input_base64), 'base64'));
828
+ input = file;
829
+ }
830
+ if (action === 'verify') {
831
+ const certificates = jsonObjectOf(body.certificates) ?? {};
832
+ const certificate = textOf(certificates[target]);
833
+ if (certificate)
834
+ options.identity = AID._create({ aid: target, aunPath: this.aunPath, certPem: certificate, privateKeyPem: null, certValid: true, privateKeyValid: false });
835
+ if (options.format === 'document')
836
+ options.certificateResolver = (signer) => {
837
+ const certificate = textOf(certificates[signer]);
838
+ if (!certificate)
839
+ throw new Error(`certificate unavailable: ${signer}`);
840
+ return certificate;
841
+ };
842
+ }
843
+ const operation = action === 'sign'
844
+ ? await store.sign(target, input, options)
845
+ : await store.verify(target, input, body.signature == null ? undefined : textOf(body.signature), options);
846
+ if (!operation.ok) {
847
+ const response = { ok: false, error_code: operation.error.code, error_message: operation.error.message };
848
+ if (file)
849
+ response.file_base64 = fs.readFileSync(file).toString('base64');
850
+ sendJson(res, 200, response);
851
+ return;
852
+ }
853
+ const loaded = options.identity ? { ok: true, data: { aid: options.identity } } : store.load(target);
854
+ const identity = loaded.ok ? loaded.data.aid : undefined;
855
+ const response = { ok: true, result: jsonSafe(operation.data), certificate: identity?.certPem ?? '', cert_fingerprint: identity?.certFingerprint ?? '' };
856
+ if (file)
857
+ response.file_base64 = fs.readFileSync(file).toString('base64');
858
+ sendJson(res, 200, response);
859
+ }
860
+ catch (error) {
861
+ const response = { ok: false, error_code: error instanceof Error ? error.name : 'Error', error_message: error instanceof Error ? error.message : String(error) };
862
+ if (file && fs.existsSync(file))
863
+ response.file_base64 = fs.readFileSync(file).toString('base64');
864
+ sendJson(res, 200, response);
865
+ }
866
+ finally {
867
+ store.close();
868
+ if (file)
869
+ fs.unlinkSync(file);
870
+ if (directory)
871
+ fs.rmdirSync(directory);
872
+ }
873
+ }
621
874
  async send(req, res) {
622
875
  const body = await readJson(req);
623
876
  const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
@@ -721,6 +974,39 @@ class CrossSdkTsAgent {
721
974
  });
722
975
  }
723
976
  }
977
+ async messageCall(req, res) {
978
+ const body = await readJson(req);
979
+ const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
980
+ const method = textOf(body.method).trim();
981
+ const params = jsonObjectOf(body.params) ?? {};
982
+ if (!method) {
983
+ sendJson(res, 400, { ok: false, trace_id: traceId, error_code: 'bad_request', error_message: 'method is required' });
984
+ return;
985
+ }
986
+ try {
987
+ let result;
988
+ if (method === 'message.read')
989
+ result = await this.client.message.read(params);
990
+ else if (method === 'message.read_state')
991
+ result = await this.client.message.readState(params);
992
+ else
993
+ result = await this.client.call(method, params);
994
+ const response = { ok: true, trace_id: traceId, method, result: jsonSafe(result) };
995
+ this.recordTrace(traceId, { stage: 'message_call', method, result: response });
996
+ sendJson(res, 200, response);
997
+ }
998
+ catch (err) {
999
+ const error = {
1000
+ ok: false,
1001
+ trace_id: traceId,
1002
+ method,
1003
+ error_code: err instanceof Error ? err.name : 'Error',
1004
+ error_message: err instanceof Error ? err.message : String(err),
1005
+ };
1006
+ this.recordTrace(traceId, { stage: 'message_call_error', method, error });
1007
+ sendJson(res, 500, error);
1008
+ }
1009
+ }
724
1010
  syncNamespace(scope, groupId = '') {
725
1011
  if (scope === 'p2p')
726
1012
  return `p2p:${this.aid}`;
@@ -940,6 +1226,84 @@ class CrossSdkTsAgent {
940
1226
  store.close();
941
1227
  }
942
1228
  }
1229
+ async orgProtocol(params) {
1230
+ const op = textOf(params.op);
1231
+ const now = Math.floor(Date.now() / 1000);
1232
+ if (op === 'request')
1233
+ return buildRequestBinding(textOf(params.method), textOf(params.target), params.params, textOf(params.credential_cid), textOf(params.nonce), textOf(params.request_id), now, now + 300);
1234
+ if (['register', 'sign', 'certificate', 'create', 'prepare'].includes(op)) {
1235
+ const store = this.aidStore();
1236
+ try {
1237
+ if (op === 'prepare') {
1238
+ const request = jsonObjectOf(params.params) ?? {};
1239
+ const orgId = textOf(params.org_id ?? request.org_id);
1240
+ const loaded = orgId ? store.load(orgId) : null;
1241
+ const orgSigner = loaded?.ok && loaded.data.aid.isPrivateKeyValid() ? loaded.data.aid : undefined;
1242
+ return this.client.org.prepareRequest(textOf(params.method), request, textOf(params.target), this.client.currentAid, { ...jsonObjectOf(params.options), orgSigner });
1243
+ }
1244
+ if (op === 'register') {
1245
+ const registered = await store.register(textOf(params.org_id), { type: 'org', owner: this.aid, exttype: 'company' });
1246
+ if (!registered.ok)
1247
+ throw new Error(String(registered.error));
1248
+ }
1249
+ const loaded = op === 'certificate'
1250
+ ? await store.resolve(textOf(params.as_aid), { skipAgentMd: true })
1251
+ : (params.as_aid || params.org_id) ? store.load(textOf(params.as_aid ?? params.org_id)) : null;
1252
+ if (loaded && !loaded.ok)
1253
+ throw new Error(String(loaded.error));
1254
+ const identity = loaded?.data?.aid ?? this.client.currentAid;
1255
+ const result = { cert_fingerprint: identity.certFingerprint, certificate: identity.certPem };
1256
+ if (op === 'sign') {
1257
+ const signed = await identity.sign(Buffer.from(canonicalJson(params.payload)));
1258
+ if (!signed.ok)
1259
+ throw new Error(String(signed.error));
1260
+ result.signature = { cert_fingerprint: identity.certFingerprint, timestamp: now, signature: signed.data.signature };
1261
+ }
1262
+ else if (op === 'create') {
1263
+ result.credential = params.membership_binding
1264
+ ? this.client.org.member.createCredential(params.membership_binding, identity, params.options)
1265
+ : this.client.credential.create(params.options, identity);
1266
+ }
1267
+ return result;
1268
+ }
1269
+ finally {
1270
+ store.close();
1271
+ }
1272
+ }
1273
+ const value = params.document ?? params.payload;
1274
+ const result = { canonical: new TextDecoder().decode(canonicalJson(value)), digest: digest(value), error_code: '' };
1275
+ if (op === 'verify' || op === 'verify_full') {
1276
+ const verificationNow = typeof params.now === 'number' ? params.now : now;
1277
+ const certificates = params.certificates;
1278
+ const resolver = (fingerprint) => certificates[fingerprint];
1279
+ try {
1280
+ if (op === 'verify_full') {
1281
+ const actual = jsonObjectOf(params.context) ?? params;
1282
+ const memberships = jsonObjectOf(params.memberships) ?? {};
1283
+ result.verification = { ...this.client.credential.verify(value, { resolveCertificate: resolver, resolveActorCertificate: resolver,
1284
+ resolveStatus: (cid) => params.statuses?.[cid], now: verificationNow, audience: textOf(actual.audience), subject: textOf(actual.subject) || undefined,
1285
+ ns: textOf(actual.ns), action: textOf(actual.action), resource: textOf(actual.resource), rootIssuer: textOf(actual.root_issuer) || undefined,
1286
+ params: jsonObjectOf(actual.params) ?? {}, units: jsonObjectOf(actual.units) ?? {}, clientIp: textOf(actual.client_ip), method: textOf(actual.method), target: textOf(actual.target),
1287
+ requestId: textOf(actual.request_id), nonce: textOf(actual.nonce), requestBinding: actual.request_binding, proofChain: actual.proof_chain, membershipBinding: actual.membership_binding,
1288
+ orgSigner: textOf(actual.org_signer) || undefined, actor: textOf(actual.actor) || undefined, for: textOf(actual.for) || undefined, representationProof: actual.representation_proof,
1289
+ resolveMembershipStatus: (binding, credential) => { const current = jsonObjectOf(memberships[String(binding.membership_id)]); return current?.status === 'active' && current.credential_cid === credential.cid; },
1290
+ resolveOwnership: (subject, owner) => (jsonObjectOf(params.ownerships) ?? {})[subject] === owner, checkRateLimit: () => params.rate_limit_allowed === true }) };
1291
+ }
1292
+ else if (params.kind === 'credential')
1293
+ result.verification = { ...this.client.credential.verifySignature(value, resolver, verificationNow, textOf(params.audience)) };
1294
+ else if (params.kind === 'binding')
1295
+ await verifyMembershipBinding(value, resolver, verificationNow, textOf(params.expected_org_signer));
1296
+ else
1297
+ result.verification = { ...this.client.credential.verifyRegistrationReceipt(value, params.credential, params.request, resolver, textOf(params.service_aid), verificationNow) };
1298
+ }
1299
+ catch (error) {
1300
+ if (!(error instanceof ProtocolError))
1301
+ throw error;
1302
+ result.error_code = error.code;
1303
+ }
1304
+ }
1305
+ return result;
1306
+ }
943
1307
  async groupCall(req, res) {
944
1308
  const body = await readJson(req);
945
1309
  const traceId = textOf(body.trace_id || crypto.randomUUID().replace(/-/g, ''));
@@ -955,6 +1319,48 @@ class CrossSdkTsAgent {
955
1319
  try {
956
1320
  let result;
957
1321
  switch (method) {
1322
+ case 'sdk.org.protocol':
1323
+ result = await this.orgProtocol(params);
1324
+ break;
1325
+ case 'org.lifecycle.create':
1326
+ result = await this.client.org.lifecycle.create(params);
1327
+ break;
1328
+ case 'org.lifecycle.dissolve':
1329
+ result = await this.client.org.lifecycle.dissolve(params);
1330
+ break;
1331
+ case 'org.lifecycle.transfer':
1332
+ result = await this.client.org.lifecycle.transfer(params);
1333
+ break;
1334
+ case 'org.lifecycle.transferAccept':
1335
+ result = await this.client.org.lifecycle.transferAccept(params);
1336
+ break;
1337
+ case 'org.member.join':
1338
+ result = await this.client.org.member.join(params);
1339
+ break;
1340
+ case 'org.member.approveJoin':
1341
+ result = await this.client.org.member.approveJoin(params);
1342
+ break;
1343
+ case 'org.member.rejectJoin':
1344
+ result = await this.client.org.member.rejectJoin(params);
1345
+ break;
1346
+ case 'org.member.invite':
1347
+ result = await this.client.org.member.invite(params);
1348
+ break;
1349
+ case 'org.member.inviteAccept':
1350
+ result = await this.client.org.member.inviteAccept(params);
1351
+ break;
1352
+ case 'org.member.inviteReject':
1353
+ result = await this.client.org.member.inviteReject(params);
1354
+ break;
1355
+ case 'org.member.leave':
1356
+ result = await this.client.org.member.leave(params);
1357
+ break;
1358
+ case 'org.member.offboard':
1359
+ result = await this.client.org.member.offboard(params);
1360
+ break;
1361
+ case 'org.credential.getStatus':
1362
+ result = await this.client.org.credential.getStatus(params);
1363
+ break;
958
1364
  case 'sdk.update_group_index':
959
1365
  result = await this.client.group.updateGroupIndex(params);
960
1366
  break;
@@ -988,6 +1394,12 @@ class CrossSdkTsAgent {
988
1394
  case 'group.get_member_statuses':
989
1395
  result = await this.client.group.getMemberStatuses(params);
990
1396
  break;
1397
+ case 'group.read':
1398
+ result = await this.client.group.read(params);
1399
+ break;
1400
+ case 'group.read_state':
1401
+ result = await this.client.group.readState(params);
1402
+ break;
991
1403
  default: result = await this.client.call(method, params);
992
1404
  }
993
1405
  const response = { ok: true, trace_id: traceId, method, result: jsonSafe(result) };
@@ -1750,6 +2162,27 @@ class CrossSdkTsAgent {
1750
2162
  '',
1751
2163
  ].join('\n');
1752
2164
  }
2165
+ agentMdContentForUpload(aid, name, type, description) {
2166
+ let content = '';
2167
+ try {
2168
+ const manager = this.client._agentMdManager;
2169
+ const managed = manager?.readContent?.(aid);
2170
+ content = typeof managed === 'string' ? managed : '';
2171
+ }
2172
+ catch {
2173
+ content = '';
2174
+ }
2175
+ if (content && (content.includes('owner:') || content.includes('ownership_proof:') || content.includes('ownership_release:')))
2176
+ return content;
2177
+ try {
2178
+ content = fs.readFileSync(path.join(this.aunPath, 'AIDs', aid, 'agent.md'), 'utf-8');
2179
+ if (content.includes('owner:') || content.includes('ownership_proof:') || content.includes('ownership_release:'))
2180
+ return content;
2181
+ }
2182
+ catch {
2183
+ }
2184
+ return this.agentMdContent(aid, name, type, description);
2185
+ }
1753
2186
  aidStore() {
1754
2187
  return new AIDStore({
1755
2188
  aunPath: this.aunPath,
@@ -1834,5 +2267,6 @@ async function main() {
1834
2267
  process.on('SIGINT', () => { void shutdown(); });
1835
2268
  process.on('SIGTERM', () => { void shutdown(); });
1836
2269
  }
1837
- void main();
2270
+ if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url))
2271
+ void main();
1838
2272
  //# sourceMappingURL=cross-sdk-agent.js.map