@dp-pcs/ogp 0.9.0 → 0.10.0
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/dist/cli/agent-comms.d.ts +1 -1
- package/dist/cli/agent-comms.d.ts.map +1 -1
- package/dist/cli/agent-comms.js +9 -2
- package/dist/cli/agent-comms.js.map +1 -1
- package/dist/cli/config.d.ts +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +81 -1
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/federation.d.ts +47 -3
- package/dist/cli/federation.d.ts.map +1 -1
- package/dist/cli/federation.js +219 -62
- package/dist/cli/federation.js.map +1 -1
- package/dist/cli/tunnel.d.ts +7 -1
- package/dist/cli/tunnel.d.ts.map +1 -1
- package/dist/cli/tunnel.js +12 -3
- package/dist/cli/tunnel.js.map +1 -1
- package/dist/cli.js +63 -20
- package/dist/cli.js.map +1 -1
- package/dist/daemon/agent-comms.d.ts +9 -0
- package/dist/daemon/agent-comms.d.ts.map +1 -1
- package/dist/daemon/agent-comms.js +65 -0
- package/dist/daemon/agent-comms.js.map +1 -1
- package/dist/daemon/relay-client.d.ts +16 -0
- package/dist/daemon/relay-client.d.ts.map +1 -0
- package/dist/daemon/relay-client.js +312 -0
- package/dist/daemon/relay-client.js.map +1 -0
- package/dist/daemon/rendezvous.d.ts +56 -2
- package/dist/daemon/rendezvous.d.ts.map +1 -1
- package/dist/daemon/rendezvous.js +99 -4
- package/dist/daemon/rendezvous.js.map +1 -1
- package/dist/daemon/server.d.ts +1 -0
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +140 -26
- package/dist/daemon/server.js.map +1 -1
- package/dist/shared/config.d.ts +28 -0
- package/dist/shared/config.d.ts.map +1 -1
- package/dist/shared/config.js +7 -0
- package/dist/shared/config.js.map +1 -1
- package/dist/shared/meta-config.d.ts.map +1 -1
- package/dist/shared/meta-config.js +23 -9
- package/dist/shared/meta-config.js.map +1 -1
- package/dist/shared/relay-protocol.d.ts +91 -0
- package/dist/shared/relay-protocol.d.ts.map +1 -0
- package/dist/shared/relay-protocol.js +55 -0
- package/dist/shared/relay-protocol.js.map +1 -0
- package/docs/CLI-REFERENCE.md +38 -0
- package/docs/TRANSPORT-MODES-DESIGN.md +164 -0
- package/package.json +1 -1
package/dist/cli/federation.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { listPeers, loadPeers, getPeer, approvePeer, rejectPeer, updatePeer, updatePeerGrantedScopes } from '../daemon/peers.js';
|
|
2
2
|
import { requireConfig, loadConfig } from '../shared/config.js';
|
|
3
|
-
import { lookupPeer } from '../daemon/rendezvous.js';
|
|
3
|
+
import { lookupPeer, lookupPeerTransport } from '../daemon/rendezvous.js';
|
|
4
|
+
import { deliverViaRelay } from '../daemon/relay-client.js';
|
|
4
5
|
import { getPublicKey, getPrivateKey, loadOrGenerateKeyPair } from '../daemon/keypair.js';
|
|
5
6
|
import { signObject, sign } from '../shared/signing.js';
|
|
6
7
|
import * as crypto from 'node:crypto';
|
|
@@ -144,7 +145,24 @@ function resolvePeerId(identifier) {
|
|
|
144
145
|
}
|
|
145
146
|
return null;
|
|
146
147
|
}
|
|
147
|
-
|
|
148
|
+
/** Pure projection of peers to the stable `--json` wire shape. */
|
|
149
|
+
export function peersToJson(peers) {
|
|
150
|
+
return peers.map(p => ({
|
|
151
|
+
id: p.id,
|
|
152
|
+
alias: p.alias,
|
|
153
|
+
displayName: p.displayName,
|
|
154
|
+
status: p.status,
|
|
155
|
+
gatewayUrl: p.gatewayUrl,
|
|
156
|
+
publicKey: p.publicKey,
|
|
157
|
+
healthState: p.healthState,
|
|
158
|
+
healthy: p.healthy,
|
|
159
|
+
grantedScopes: p.grantedScopes,
|
|
160
|
+
offeredIntents: p.offeredIntents,
|
|
161
|
+
lastSeenAt: p.lastSeenAt,
|
|
162
|
+
tags: p.tags,
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
export async function federationList(status, filterTag, json = false) {
|
|
148
166
|
// Check if --for all was specified
|
|
149
167
|
if (process.env.OGP_FOR_ALL === 'true') {
|
|
150
168
|
const metaConfig = loadMetaConfig();
|
|
@@ -153,10 +171,14 @@ export async function federationList(status, filterTag) {
|
|
|
153
171
|
console.error('Error: No enabled frameworks found. Run "ogp setup" first.');
|
|
154
172
|
process.exit(1);
|
|
155
173
|
}
|
|
174
|
+
// Accumulator for --json output (per-framework peers).
|
|
175
|
+
const perFramework = [];
|
|
156
176
|
// Print header
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
177
|
+
if (!json) {
|
|
178
|
+
console.log('\n═══════════════════════════════════════════════════════════════');
|
|
179
|
+
console.log(`Federation Peers (All Frameworks)`);
|
|
180
|
+
console.log('═══════════════════════════════════════════════════════════════\n');
|
|
181
|
+
}
|
|
160
182
|
let totalPeers = 0;
|
|
161
183
|
// Iterate through each framework
|
|
162
184
|
for (const framework of enabledFrameworks) {
|
|
@@ -165,15 +187,25 @@ export async function federationList(status, filterTag) {
|
|
|
165
187
|
try {
|
|
166
188
|
const config = loadConfig();
|
|
167
189
|
if (!config) {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
190
|
+
if (json) {
|
|
191
|
+
perFramework.push({ framework: framework.id, peers: [] });
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
console.log(`${framework.name} (${framework.displayName || framework.id})`);
|
|
195
|
+
console.log('───────────────────────────────────────────────────────────────');
|
|
196
|
+
console.log(' No config found - run setup');
|
|
197
|
+
console.log('');
|
|
198
|
+
}
|
|
172
199
|
continue;
|
|
173
200
|
}
|
|
174
201
|
// Load peers for this framework
|
|
175
202
|
const allPeers = loadPeers();
|
|
176
203
|
const peers = status ? allPeers.filter(p => p.status === status) : allPeers.filter(p => p.status !== 'removed');
|
|
204
|
+
if (json) {
|
|
205
|
+
totalPeers += peers.length;
|
|
206
|
+
perFramework.push({ framework: framework.id, peers: peersToJson(peers) });
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
177
209
|
// Print framework header
|
|
178
210
|
console.log(`${framework.name} (${framework.displayName || framework.id})`);
|
|
179
211
|
console.log('───────────────────────────────────────────────────────────────');
|
|
@@ -211,10 +243,15 @@ export async function federationList(status, filterTag) {
|
|
|
211
243
|
console.log('');
|
|
212
244
|
}
|
|
213
245
|
catch (error) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
246
|
+
if (json) {
|
|
247
|
+
perFramework.push({ framework: framework.id, peers: [] });
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
console.log(`${framework.name} (${framework.displayName || framework.id})`);
|
|
251
|
+
console.log('───────────────────────────────────────────────────────────────');
|
|
252
|
+
console.log(` Error: ${error.message}`);
|
|
253
|
+
console.log('');
|
|
254
|
+
}
|
|
218
255
|
}
|
|
219
256
|
finally {
|
|
220
257
|
// Restore original OGP_HOME
|
|
@@ -226,6 +263,10 @@ export async function federationList(status, filterTag) {
|
|
|
226
263
|
}
|
|
227
264
|
}
|
|
228
265
|
}
|
|
266
|
+
if (json) {
|
|
267
|
+
console.log(JSON.stringify(perFramework, null, 2));
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
229
270
|
console.log(`Total: ${totalPeers} peer${totalPeers !== 1 ? 's' : ''} across ${enabledFrameworks.length} framework${enabledFrameworks.length !== 1 ? 's' : ''}`);
|
|
230
271
|
return;
|
|
231
272
|
}
|
|
@@ -237,6 +278,10 @@ export async function federationList(status, filterTag) {
|
|
|
237
278
|
if (filterTag) {
|
|
238
279
|
peers = peers.filter(p => p.tags && p.tags.includes(filterTag));
|
|
239
280
|
}
|
|
281
|
+
if (json) {
|
|
282
|
+
console.log(JSON.stringify(peersToJson(peers), null, 2));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
240
285
|
if (peers.length === 0) {
|
|
241
286
|
console.log('No peers found.');
|
|
242
287
|
return;
|
|
@@ -300,7 +345,7 @@ export async function federationList(status, filterTag) {
|
|
|
300
345
|
console.log('');
|
|
301
346
|
});
|
|
302
347
|
}
|
|
303
|
-
export async function federationStatus() {
|
|
348
|
+
export async function federationStatus(json = false) {
|
|
304
349
|
// Check if --for all was specified
|
|
305
350
|
if (process.env.OGP_FOR_ALL === 'true') {
|
|
306
351
|
const metaConfig = loadMetaConfig();
|
|
@@ -309,6 +354,42 @@ export async function federationStatus() {
|
|
|
309
354
|
console.error('Error: No enabled frameworks found. Run "ogp setup" first.');
|
|
310
355
|
process.exit(1);
|
|
311
356
|
}
|
|
357
|
+
// --json across all frameworks: emit a per-framework array (mirrors federationList).
|
|
358
|
+
if (json) {
|
|
359
|
+
const perFramework = [];
|
|
360
|
+
for (const framework of enabledFrameworks) {
|
|
361
|
+
const originalOgpHome = process.env.OGP_HOME;
|
|
362
|
+
process.env.OGP_HOME = expandTilde(framework.configDir);
|
|
363
|
+
try {
|
|
364
|
+
const config = loadConfig();
|
|
365
|
+
if (!config) {
|
|
366
|
+
perFramework.push({ framework: framework.id, total: 0, approved: [], pending: [], rejected: [] });
|
|
367
|
+
continue;
|
|
368
|
+
}
|
|
369
|
+
const fwPeers = listPeers();
|
|
370
|
+
perFramework.push({
|
|
371
|
+
framework: framework.id,
|
|
372
|
+
total: fwPeers.length,
|
|
373
|
+
approved: peersToJson(fwPeers.filter(p => p.status === 'approved')),
|
|
374
|
+
pending: peersToJson(fwPeers.filter(p => p.status === 'pending')),
|
|
375
|
+
rejected: peersToJson(fwPeers.filter(p => p.status === 'rejected')),
|
|
376
|
+
});
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
perFramework.push({ framework: framework.id, total: 0, approved: [], pending: [], rejected: [] });
|
|
380
|
+
}
|
|
381
|
+
finally {
|
|
382
|
+
if (originalOgpHome) {
|
|
383
|
+
process.env.OGP_HOME = originalOgpHome;
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
delete process.env.OGP_HOME;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
console.log(JSON.stringify(perFramework, null, 2));
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
312
393
|
// Print header
|
|
313
394
|
console.log('\n═══════════════════════════════════════════════════════════════');
|
|
314
395
|
console.log(`Federation Status (All Frameworks)`);
|
|
@@ -404,6 +485,15 @@ export async function federationStatus() {
|
|
|
404
485
|
const pendingPeers = peers.filter(p => p.status === 'pending');
|
|
405
486
|
const rejectedPeers = peers.filter(p => p.status === 'rejected');
|
|
406
487
|
const removedPeers = peers.filter(p => p.status === 'removed');
|
|
488
|
+
if (json) {
|
|
489
|
+
console.log(JSON.stringify({
|
|
490
|
+
total: peers.length,
|
|
491
|
+
approved: peersToJson(approvedPeers),
|
|
492
|
+
pending: peersToJson(pendingPeers),
|
|
493
|
+
rejected: peersToJson(rejectedPeers),
|
|
494
|
+
}, null, 2));
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
407
497
|
// Health statistics for approved peers (Issue #3: directional)
|
|
408
498
|
const stateCounts = {
|
|
409
499
|
established: 0,
|
|
@@ -485,10 +575,12 @@ export async function federationStatus() {
|
|
|
485
575
|
}
|
|
486
576
|
}
|
|
487
577
|
}
|
|
488
|
-
export async function federationRequest(peerUrl, peerId, alias) {
|
|
578
|
+
export async function federationRequest(peerUrl, peerId, alias, json = false) {
|
|
489
579
|
const config = requireConfig();
|
|
490
580
|
const keypair = loadOrGenerateKeyPair();
|
|
491
581
|
if (!await ensureLocalGatewayReachable(config, 'send federation requests')) {
|
|
582
|
+
if (json)
|
|
583
|
+
console.log(JSON.stringify({ ok: false, peerUrl, peerId, status: 'failed', error: 'local gateway not reachable' }));
|
|
492
584
|
return false;
|
|
493
585
|
}
|
|
494
586
|
// BUILD-111: Use public key prefix as peer ID (port-agnostic identity)
|
|
@@ -501,7 +593,12 @@ export async function federationRequest(peerUrl, peerId, alias) {
|
|
|
501
593
|
peerCard = resolved.card;
|
|
502
594
|
}
|
|
503
595
|
catch (error) {
|
|
504
|
-
|
|
596
|
+
if (json) {
|
|
597
|
+
console.log(JSON.stringify({ ok: false, peerUrl, peerId, status: 'failed', error: error.message }));
|
|
598
|
+
}
|
|
599
|
+
else {
|
|
600
|
+
console.error(error.message);
|
|
601
|
+
}
|
|
505
602
|
return false;
|
|
506
603
|
}
|
|
507
604
|
// Build our peer info
|
|
@@ -536,13 +633,20 @@ export async function federationRequest(peerUrl, peerId, alias) {
|
|
|
536
633
|
body: JSON.stringify(requestBody)
|
|
537
634
|
});
|
|
538
635
|
if (!response.ok) {
|
|
539
|
-
|
|
636
|
+
if (json) {
|
|
637
|
+
console.log(JSON.stringify({ ok: false, peerUrl: resolvedPeerUrl, peerId, status: 'failed', error: `${response.status} ${response.statusText}` }));
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
console.error(`Request failed: ${response.status} ${response.statusText}`);
|
|
641
|
+
}
|
|
540
642
|
return false;
|
|
541
643
|
}
|
|
542
644
|
const result = await response.json();
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
645
|
+
if (!json) {
|
|
646
|
+
console.log('✓ Federation request sent');
|
|
647
|
+
console.log(` Status: ${result.status}`);
|
|
648
|
+
console.log(` Message: ${result.message}`);
|
|
649
|
+
}
|
|
546
650
|
// Fetch their federation card to get their actual identity
|
|
547
651
|
// Store them as a pending peer so we can send intents when approved
|
|
548
652
|
try {
|
|
@@ -570,10 +674,18 @@ export async function federationRequest(peerUrl, peerId, alias) {
|
|
|
570
674
|
}
|
|
571
675
|
}
|
|
572
676
|
catch { /* non-fatal */ }
|
|
677
|
+
if (json) {
|
|
678
|
+
console.log(JSON.stringify({ ok: true, peerUrl: resolvedPeerUrl, peerId, status: result.status ?? 'requested', message: result.message }));
|
|
679
|
+
}
|
|
573
680
|
return true;
|
|
574
681
|
}
|
|
575
682
|
catch (error) {
|
|
576
|
-
|
|
683
|
+
if (json) {
|
|
684
|
+
console.log(JSON.stringify({ ok: false, peerUrl: resolvedPeerUrl, peerId, status: 'failed', error: error instanceof Error ? error.message : String(error) }));
|
|
685
|
+
}
|
|
686
|
+
else {
|
|
687
|
+
console.error('Failed to send request:', error);
|
|
688
|
+
}
|
|
577
689
|
return false;
|
|
578
690
|
}
|
|
579
691
|
}
|
|
@@ -831,6 +943,79 @@ export async function federationRemove(peerId) {
|
|
|
831
943
|
removePeer(peerId);
|
|
832
944
|
console.log(`✓ Removed peer: ${peerId} (${peer.displayName})`);
|
|
833
945
|
}
|
|
946
|
+
/**
|
|
947
|
+
* Deliver an already-signed federation envelope to a peer, branching on the
|
|
948
|
+
* peer's advertised transport (bd-b7em Phase 2).
|
|
949
|
+
*
|
|
950
|
+
* - DIRECT (default, and the fallback for everything): byte-identical to the
|
|
951
|
+
* original behavior — POST {message, messageStr, signature} to
|
|
952
|
+
* `${peer.gatewayUrl}/federation/message`. A flaky/disabled rendezvous lookup
|
|
953
|
+
* MUST fall through to direct so it can never break the default path.
|
|
954
|
+
* - RELAY: route the same opaque frame over a WebSocket to the relay, which
|
|
955
|
+
* forwards it to the peer's persistent socket and returns their response.
|
|
956
|
+
*
|
|
957
|
+
* Returns a normalized shape so callers can keep their existing response
|
|
958
|
+
* handling: { ok, status?, result }. `result` is the peer's MessageResponse
|
|
959
|
+
* (or a synthesized failure for relay errors).
|
|
960
|
+
*/
|
|
961
|
+
export async function deliverFederationMessage(peer, frame, opts) {
|
|
962
|
+
// Resolve transport. Any failure (rendezvous disabled, lookup throws/null,
|
|
963
|
+
// direct, or iroh) ⇒ direct. Relay never preempts the default unless the peer
|
|
964
|
+
// explicitly advertised a relay descriptor inside their signed registration.
|
|
965
|
+
let relayUrl = null;
|
|
966
|
+
if (opts.config.rendezvous?.enabled && peer.publicKey) {
|
|
967
|
+
try {
|
|
968
|
+
const resolved = await lookupPeerTransport(opts.config.rendezvous, peer.publicKey);
|
|
969
|
+
if (resolved && resolved.mode === 'relay')
|
|
970
|
+
relayUrl = resolved.relayUrl;
|
|
971
|
+
}
|
|
972
|
+
catch {
|
|
973
|
+
// fall through to direct — a flaky rendezvous must not break direct sends
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
if (relayUrl) {
|
|
977
|
+
try {
|
|
978
|
+
const result = await deliverViaRelay(relayUrl, peer.publicKey, frame, opts.timeoutMs);
|
|
979
|
+
const r = result;
|
|
980
|
+
return { ok: r?.success !== false, status: r?.statusCode, result };
|
|
981
|
+
}
|
|
982
|
+
catch (err) {
|
|
983
|
+
return {
|
|
984
|
+
ok: false,
|
|
985
|
+
result: { success: false, error: `peer not connected via relay: ${err.message}` }
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
// DIRECT PATH — unchanged wire behavior.
|
|
990
|
+
const controller = new AbortController();
|
|
991
|
+
const timeoutId = opts.timeoutMs ? setTimeout(() => controller.abort(), opts.timeoutMs) : null;
|
|
992
|
+
try {
|
|
993
|
+
const response = await fetch(`${peer.gatewayUrl}/federation/message`, {
|
|
994
|
+
method: 'POST',
|
|
995
|
+
headers: { 'Content-Type': 'application/json' },
|
|
996
|
+
body: JSON.stringify({
|
|
997
|
+
message: frame.message,
|
|
998
|
+
messageStr: frame.messageStr, // raw signed string for exact verification
|
|
999
|
+
signature: frame.signature
|
|
1000
|
+
}),
|
|
1001
|
+
signal: controller.signal
|
|
1002
|
+
});
|
|
1003
|
+
if (timeoutId)
|
|
1004
|
+
clearTimeout(timeoutId);
|
|
1005
|
+
let result = null;
|
|
1006
|
+
try {
|
|
1007
|
+
result = await response.json();
|
|
1008
|
+
}
|
|
1009
|
+
catch {
|
|
1010
|
+
result = null;
|
|
1011
|
+
}
|
|
1012
|
+
return { ok: response.ok, status: response.status, result };
|
|
1013
|
+
}
|
|
1014
|
+
finally {
|
|
1015
|
+
if (timeoutId)
|
|
1016
|
+
clearTimeout(timeoutId);
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
834
1019
|
export async function federationSend(peerId, intent, payloadJson, timeoutMs, toAgent) {
|
|
835
1020
|
const config = requireConfig();
|
|
836
1021
|
// Resolve peer identifier (alias, ID, or public key)
|
|
@@ -872,37 +1057,17 @@ export async function federationSend(peerId, intent, payloadJson, timeoutMs, toA
|
|
|
872
1057
|
};
|
|
873
1058
|
const { payload: signedPayload, payloadStr, signature } = signObject(message, getPrivateKey());
|
|
874
1059
|
try {
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
const response = await fetch(`${peer.gatewayUrl}/federation/message`, {
|
|
878
|
-
method: 'POST',
|
|
879
|
-
headers: { 'Content-Type': 'application/json' },
|
|
880
|
-
body: JSON.stringify({
|
|
881
|
-
message: signedPayload,
|
|
882
|
-
messageStr: payloadStr, // raw signed string for exact verification
|
|
883
|
-
signature
|
|
884
|
-
}),
|
|
885
|
-
signal: controller.signal
|
|
886
|
-
});
|
|
887
|
-
if (timeoutId)
|
|
888
|
-
clearTimeout(timeoutId);
|
|
889
|
-
let result = null;
|
|
890
|
-
try {
|
|
891
|
-
result = await response.json();
|
|
892
|
-
}
|
|
893
|
-
catch {
|
|
894
|
-
result = null;
|
|
895
|
-
}
|
|
896
|
-
if (!response.ok) {
|
|
1060
|
+
const { ok, status, result } = await deliverFederationMessage(peer, { message: signedPayload, messageStr: payloadStr, signature }, { timeoutMs, config });
|
|
1061
|
+
if (!ok) {
|
|
897
1062
|
if (result?.error) {
|
|
898
|
-
console.error(`Send failed: ${
|
|
1063
|
+
console.error(`Send failed: ${status ? `${status} ` : ''}${result.error}`);
|
|
899
1064
|
return result;
|
|
900
1065
|
}
|
|
901
|
-
console.error(`Send failed
|
|
1066
|
+
console.error(`Send failed${status ? `: ${status}` : ''}`);
|
|
902
1067
|
return {
|
|
903
1068
|
success: false,
|
|
904
|
-
error: `Send failed
|
|
905
|
-
statusCode:
|
|
1069
|
+
error: `Send failed${status ? `: ${status}` : ''}`,
|
|
1070
|
+
statusCode: status
|
|
906
1071
|
};
|
|
907
1072
|
}
|
|
908
1073
|
return result;
|
|
@@ -1214,30 +1379,22 @@ export async function federationSendAgentComms(peerId, topic, messageText, optio
|
|
|
1214
1379
|
};
|
|
1215
1380
|
const { payload: signedPayload, payloadStr, signature } = signObject(message, getPrivateKey());
|
|
1216
1381
|
try {
|
|
1217
|
-
const
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
message: signedPayload,
|
|
1222
|
-
messageStr: payloadStr, // raw signed string for exact verification
|
|
1223
|
-
signature
|
|
1224
|
-
})
|
|
1225
|
-
});
|
|
1226
|
-
if (!response.ok) {
|
|
1227
|
-
const body = await response.text();
|
|
1228
|
-
if (response.status === 403) {
|
|
1382
|
+
const { ok, status, result: delivered } = await deliverFederationMessage(peer, { message: signedPayload, messageStr: payloadStr, signature }, { config });
|
|
1383
|
+
if (!ok) {
|
|
1384
|
+
const body = delivered?.error ? String(delivered.error) : (delivered ? JSON.stringify(delivered) : '');
|
|
1385
|
+
if (status === 403) {
|
|
1229
1386
|
console.error(`Access denied: ${body}`);
|
|
1230
1387
|
console.log('Hint: Peer may not have granted you agent-comms scope for this topic.');
|
|
1231
1388
|
}
|
|
1232
|
-
else if (
|
|
1389
|
+
else if (status === 429) {
|
|
1233
1390
|
console.error(`Rate limited: ${body}`);
|
|
1234
1391
|
}
|
|
1235
1392
|
else {
|
|
1236
|
-
console.error(`Send failed
|
|
1393
|
+
console.error(`Send failed${status ? `: ${status}` : ''}${body ? ` - ${body}` : ''}`);
|
|
1237
1394
|
}
|
|
1238
1395
|
return;
|
|
1239
1396
|
}
|
|
1240
|
-
const result =
|
|
1397
|
+
const result = (delivered ?? {});
|
|
1241
1398
|
logActivity({
|
|
1242
1399
|
direction: 'out',
|
|
1243
1400
|
peerId,
|