@rookdaemon/agora 0.3.0 → 0.4.1

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.
@@ -1,129 +1,32 @@
1
- // src/identity/keypair.ts
2
- import { sign, verify, generateKeyPairSync } from "crypto";
3
- function generateKeyPair() {
4
- const { publicKey, privateKey } = generateKeyPairSync("ed25519");
5
- return {
6
- publicKey: publicKey.export({ type: "spki", format: "der" }).toString("hex"),
7
- privateKey: privateKey.export({ type: "pkcs8", format: "der" }).toString("hex")
8
- };
9
- }
10
- function signMessage(message, privateKeyHex) {
11
- const messageBuffer = typeof message === "string" ? Buffer.from(message) : message;
12
- const privateKey = Buffer.from(privateKeyHex, "hex");
13
- const signature = sign(null, messageBuffer, {
14
- key: privateKey,
15
- format: "der",
16
- type: "pkcs8"
17
- });
18
- return signature.toString("hex");
19
- }
20
- function verifySignature(message, signatureHex, publicKeyHex) {
21
- const messageBuffer = typeof message === "string" ? Buffer.from(message) : message;
22
- const signature = Buffer.from(signatureHex, "hex");
23
- const publicKey = Buffer.from(publicKeyHex, "hex");
24
- try {
25
- return verify(null, messageBuffer, {
26
- key: publicKey,
27
- format: "der",
28
- type: "spki"
29
- }, signature);
30
- } catch {
31
- return false;
32
- }
33
- }
34
- function exportKeyPair(keyPair) {
35
- return {
36
- publicKey: keyPair.publicKey,
37
- privateKey: keyPair.privateKey
38
- };
39
- }
40
- function importKeyPair(publicKeyHex, privateKeyHex) {
41
- const hexPattern = /^[0-9a-f]+$/i;
42
- if (!hexPattern.test(publicKeyHex)) {
43
- throw new Error("Invalid public key: must be a hex string");
44
- }
45
- if (!hexPattern.test(privateKeyHex)) {
46
- throw new Error("Invalid private key: must be a hex string");
47
- }
48
- return {
49
- publicKey: publicKeyHex,
50
- privateKey: privateKeyHex
51
- };
52
- }
1
+ import {
2
+ createEnvelope,
3
+ generateKeyPair,
4
+ verifyEnvelope
5
+ } from "./chunk-D7Y66GFC.js";
53
6
 
54
7
  // src/transport/peer-config.ts
55
8
  import { readFileSync, writeFileSync, existsSync } from "fs";
56
- function loadPeerConfig(path2) {
57
- const content = readFileSync(path2, "utf-8");
9
+ function loadPeerConfig(path) {
10
+ const content = readFileSync(path, "utf-8");
58
11
  return JSON.parse(content);
59
12
  }
60
- function savePeerConfig(path2, config) {
13
+ function savePeerConfig(path, config) {
61
14
  const content = JSON.stringify(config, null, 2);
62
- writeFileSync(path2, content, "utf-8");
15
+ writeFileSync(path, content, "utf-8");
63
16
  }
64
- function initPeerConfig(path2) {
65
- if (existsSync(path2)) {
66
- return loadPeerConfig(path2);
17
+ function initPeerConfig(path) {
18
+ if (existsSync(path)) {
19
+ return loadPeerConfig(path);
67
20
  }
68
21
  const identity = generateKeyPair();
69
22
  const config = {
70
23
  identity,
71
24
  peers: {}
72
25
  };
73
- savePeerConfig(path2, config);
26
+ savePeerConfig(path, config);
74
27
  return config;
75
28
  }
76
29
 
77
- // src/message/envelope.ts
78
- import { createHash } from "crypto";
79
- function stableStringify(value) {
80
- if (value === null || value === void 0) return JSON.stringify(value);
81
- if (typeof value !== "object") return JSON.stringify(value);
82
- if (Array.isArray(value)) {
83
- return "[" + value.map(stableStringify).join(",") + "]";
84
- }
85
- const keys = Object.keys(value).sort();
86
- const pairs = keys.map((k) => JSON.stringify(k) + ":" + stableStringify(value[k]));
87
- return "{" + pairs.join(",") + "}";
88
- }
89
- function canonicalize(type, sender, timestamp, payload, inReplyTo) {
90
- const obj = { payload, sender, timestamp, type };
91
- if (inReplyTo !== void 0) {
92
- obj.inReplyTo = inReplyTo;
93
- }
94
- return stableStringify(obj);
95
- }
96
- function computeId(canonical) {
97
- return createHash("sha256").update(canonical).digest("hex");
98
- }
99
- function createEnvelope(type, sender, privateKey, payload, timestamp = Date.now(), inReplyTo) {
100
- const canonical = canonicalize(type, sender, timestamp, payload, inReplyTo);
101
- const id = computeId(canonical);
102
- const signature = signMessage(canonical, privateKey);
103
- return {
104
- id,
105
- type,
106
- sender,
107
- timestamp,
108
- ...inReplyTo !== void 0 ? { inReplyTo } : {},
109
- payload,
110
- signature
111
- };
112
- }
113
- function verifyEnvelope(envelope) {
114
- const { id, type, sender, timestamp, payload, signature, inReplyTo } = envelope;
115
- const canonical = canonicalize(type, sender, timestamp, payload, inReplyTo);
116
- const expectedId = computeId(canonical);
117
- if (id !== expectedId) {
118
- return { valid: false, reason: "id_mismatch" };
119
- }
120
- const sigValid = verifySignature(canonical, signature, sender);
121
- if (!sigValid) {
122
- return { valid: false, reason: "signature_invalid" };
123
- }
124
- return { valid: true };
125
- }
126
-
127
30
  // src/transport/http.ts
128
31
  async function sendToPeer(config, peerPublicKey, type, payload, inReplyTo) {
129
32
  const peer = config.peers.get(peerPublicKey);
@@ -149,27 +52,36 @@ async function sendToPeer(config, peerPublicKey, type, payload, inReplyTo) {
149
52
  sessionKey: `agora:${envelope.sender.substring(0, 16)}`,
150
53
  deliver: false
151
54
  };
152
- try {
153
- const response = await fetch(`${peer.url}/agent`, {
154
- method: "POST",
155
- headers: {
156
- "Authorization": `Bearer ${peer.token}`,
157
- "Content-Type": "application/json"
158
- },
159
- body: JSON.stringify(webhookPayload)
160
- });
161
- return {
162
- ok: response.ok,
163
- status: response.status,
164
- error: response.ok ? void 0 : await response.text()
165
- };
166
- } catch (err) {
167
- return {
168
- ok: false,
169
- status: 0,
170
- error: err instanceof Error ? err.message : String(err)
171
- };
55
+ const headers = {
56
+ "Content-Type": "application/json"
57
+ };
58
+ if (peer.token) {
59
+ headers["Authorization"] = `Bearer ${peer.token}`;
172
60
  }
61
+ const requestBody = JSON.stringify(webhookPayload);
62
+ for (let attempt = 0; attempt < 2; attempt++) {
63
+ try {
64
+ const response = await fetch(`${peer.url}/agent`, {
65
+ method: "POST",
66
+ headers,
67
+ body: requestBody
68
+ });
69
+ return {
70
+ ok: response.ok,
71
+ status: response.status,
72
+ error: response.ok ? void 0 : await response.text()
73
+ };
74
+ } catch (err) {
75
+ if (attempt === 1) {
76
+ return {
77
+ ok: false,
78
+ status: 0,
79
+ error: err instanceof Error ? err.message : String(err)
80
+ };
81
+ }
82
+ }
83
+ }
84
+ return { ok: false, status: 0, error: "Unexpected send failure" };
173
85
  }
174
86
  function decodeInboundEnvelope(message, knownPeers) {
175
87
  const prefix = "[AGORA_ENVELOPE]";
@@ -291,408 +203,10 @@ async function sendViaRelay(config, peerPublicKey, type, payload, inReplyTo) {
291
203
  });
292
204
  }
293
205
 
294
- // src/relay/store.ts
295
- import * as fs from "fs";
296
- import * as path from "path";
297
- var MessageStore = class {
298
- storageDir;
299
- constructor(storageDir) {
300
- this.storageDir = storageDir;
301
- fs.mkdirSync(storageDir, { recursive: true });
302
- }
303
- recipientDir(publicKey) {
304
- const safe = publicKey.replace(/[^a-zA-Z0-9_-]/g, "_");
305
- return path.join(this.storageDir, safe);
306
- }
307
- save(recipientKey, message) {
308
- const dir = this.recipientDir(recipientKey);
309
- fs.mkdirSync(dir, { recursive: true });
310
- const filename = `${Date.now()}-${crypto.randomUUID()}.json`;
311
- fs.writeFileSync(path.join(dir, filename), JSON.stringify(message));
312
- }
313
- load(recipientKey) {
314
- const dir = this.recipientDir(recipientKey);
315
- if (!fs.existsSync(dir)) return [];
316
- const files = fs.readdirSync(dir).sort();
317
- const messages = [];
318
- for (const file of files) {
319
- if (!file.endsWith(".json")) continue;
320
- try {
321
- const data = fs.readFileSync(path.join(dir, file), "utf8");
322
- messages.push(JSON.parse(data));
323
- } catch {
324
- }
325
- }
326
- return messages;
327
- }
328
- clear(recipientKey) {
329
- const dir = this.recipientDir(recipientKey);
330
- if (!fs.existsSync(dir)) return;
331
- const files = fs.readdirSync(dir);
332
- for (const file of files) {
333
- if (file.endsWith(".json")) {
334
- fs.unlinkSync(path.join(dir, file));
335
- }
336
- }
337
- }
338
- };
339
-
340
- // src/relay/server.ts
341
- import { EventEmitter } from "events";
342
- import { WebSocketServer, WebSocket as WebSocket2 } from "ws";
343
- var RelayServer = class extends EventEmitter {
344
- wss = null;
345
- agents = /* @__PURE__ */ new Map();
346
- identity;
347
- storagePeers = [];
348
- store = null;
349
- constructor(options) {
350
- super();
351
- if (options) {
352
- if ("identity" in options && options.identity) {
353
- this.identity = options.identity;
354
- } else if ("publicKey" in options && "privateKey" in options) {
355
- this.identity = { publicKey: options.publicKey, privateKey: options.privateKey };
356
- }
357
- const opts = options;
358
- if (opts.storagePeers?.length && opts.storageDir) {
359
- this.storagePeers = opts.storagePeers;
360
- this.store = new MessageStore(opts.storageDir);
361
- }
362
- }
363
- }
364
- /**
365
- * Start the relay server
366
- * @param port - Port to listen on
367
- * @param host - Optional host (default: all interfaces)
368
- */
369
- start(port, host) {
370
- return new Promise((resolve, reject) => {
371
- try {
372
- this.wss = new WebSocketServer({ port, host: host ?? "0.0.0.0" });
373
- let resolved = false;
374
- this.wss.on("error", (error) => {
375
- this.emit("error", error);
376
- if (!resolved) {
377
- resolved = true;
378
- reject(error);
379
- }
380
- });
381
- this.wss.on("listening", () => {
382
- if (!resolved) {
383
- resolved = true;
384
- resolve();
385
- }
386
- });
387
- this.wss.on("connection", (socket) => {
388
- this.handleConnection(socket);
389
- });
390
- } catch (error) {
391
- reject(error);
392
- }
393
- });
394
- }
395
- /**
396
- * Stop the relay server
397
- */
398
- async stop() {
399
- return new Promise((resolve, reject) => {
400
- if (!this.wss) {
401
- resolve();
402
- return;
403
- }
404
- for (const agent of this.agents.values()) {
405
- agent.socket.close();
406
- }
407
- this.agents.clear();
408
- this.wss.close((err) => {
409
- if (err) {
410
- reject(err);
411
- } else {
412
- this.wss = null;
413
- resolve();
414
- }
415
- });
416
- });
417
- }
418
- /**
419
- * Get all connected agents
420
- */
421
- getAgents() {
422
- return new Map(this.agents);
423
- }
424
- /**
425
- * Handle incoming connection
426
- */
427
- handleConnection(socket) {
428
- let agentPublicKey = null;
429
- socket.on("message", (data) => {
430
- try {
431
- const msg = JSON.parse(data.toString());
432
- if (msg.type === "register" && !agentPublicKey) {
433
- if (!msg.publicKey || typeof msg.publicKey !== "string") {
434
- this.sendError(socket, "Invalid registration: missing or invalid publicKey");
435
- socket.close();
436
- return;
437
- }
438
- const publicKey = msg.publicKey;
439
- const name = msg.name;
440
- agentPublicKey = publicKey;
441
- const existing = this.agents.get(publicKey);
442
- if (existing) {
443
- existing.socket.close();
444
- }
445
- const agent = {
446
- publicKey,
447
- name,
448
- socket,
449
- lastSeen: Date.now()
450
- };
451
- this.agents.set(publicKey, agent);
452
- this.emit("agent-registered", publicKey);
453
- let peers = Array.from(this.agents.values()).filter((a) => a.publicKey !== publicKey).map((a) => ({ publicKey: a.publicKey, name: a.name }));
454
- for (const storagePeer of this.storagePeers) {
455
- if (storagePeer !== publicKey && !this.agents.has(storagePeer)) {
456
- peers.push({ publicKey: storagePeer, name: void 0 });
457
- }
458
- }
459
- socket.send(JSON.stringify({
460
- type: "registered",
461
- publicKey,
462
- peers
463
- }));
464
- this.broadcastPeerEvent("peer_online", publicKey, name);
465
- if (this.store && this.storagePeers.includes(publicKey)) {
466
- const queued = this.store.load(publicKey);
467
- for (const stored of queued) {
468
- socket.send(JSON.stringify({
469
- type: "message",
470
- from: stored.from,
471
- name: stored.name,
472
- envelope: stored.envelope
473
- }));
474
- }
475
- this.store.clear(publicKey);
476
- }
477
- return;
478
- }
479
- if (!agentPublicKey) {
480
- this.sendError(socket, "Not registered: send registration message first");
481
- socket.close();
482
- return;
483
- }
484
- if (msg.type === "message") {
485
- if (!msg.to || typeof msg.to !== "string") {
486
- this.sendError(socket, 'Invalid message: missing or invalid "to" field');
487
- return;
488
- }
489
- if (!msg.envelope || typeof msg.envelope !== "object") {
490
- this.sendError(socket, 'Invalid message: missing or invalid "envelope" field');
491
- return;
492
- }
493
- const envelope = msg.envelope;
494
- const verification = verifyEnvelope(envelope);
495
- if (!verification.valid) {
496
- this.sendError(socket, `Invalid envelope: ${verification.reason || "verification failed"}`);
497
- return;
498
- }
499
- if (envelope.sender !== agentPublicKey) {
500
- this.sendError(socket, "Envelope sender does not match registered public key");
501
- return;
502
- }
503
- const senderAgent = this.agents.get(agentPublicKey);
504
- if (senderAgent) {
505
- senderAgent.lastSeen = Date.now();
506
- }
507
- if (envelope.type === "peer_list_request" && this.identity && msg.to === this.identity.publicKey) {
508
- this.handlePeerListRequest(envelope, socket, agentPublicKey);
509
- return;
510
- }
511
- const recipient = this.agents.get(msg.to);
512
- if (!recipient || recipient.socket.readyState !== WebSocket2.OPEN) {
513
- if (this.store && this.storagePeers.includes(msg.to)) {
514
- const senderAgent2 = this.agents.get(agentPublicKey);
515
- this.store.save(msg.to, {
516
- from: agentPublicKey,
517
- name: senderAgent2?.name,
518
- envelope
519
- });
520
- this.emit("message-relayed", agentPublicKey, msg.to, envelope);
521
- } else {
522
- this.sendError(socket, "Recipient not connected");
523
- }
524
- return;
525
- }
526
- try {
527
- const senderAgent2 = this.agents.get(agentPublicKey);
528
- const relayMessage = {
529
- type: "message",
530
- from: agentPublicKey,
531
- name: senderAgent2?.name,
532
- envelope
533
- };
534
- recipient.socket.send(JSON.stringify(relayMessage));
535
- this.emit("message-relayed", agentPublicKey, msg.to, envelope);
536
- } catch (err) {
537
- this.sendError(socket, "Failed to relay message");
538
- this.emit("error", err);
539
- }
540
- return;
541
- }
542
- if (msg.type === "broadcast") {
543
- if (!msg.envelope || typeof msg.envelope !== "object") {
544
- this.sendError(socket, 'Invalid broadcast: missing or invalid "envelope" field');
545
- return;
546
- }
547
- const envelope = msg.envelope;
548
- const verification = verifyEnvelope(envelope);
549
- if (!verification.valid) {
550
- this.sendError(socket, `Invalid envelope: ${verification.reason || "verification failed"}`);
551
- return;
552
- }
553
- if (envelope.sender !== agentPublicKey) {
554
- this.sendError(socket, "Envelope sender does not match registered public key");
555
- return;
556
- }
557
- const senderAgentBroadcast = this.agents.get(agentPublicKey);
558
- if (senderAgentBroadcast) {
559
- senderAgentBroadcast.lastSeen = Date.now();
560
- }
561
- const senderAgent = this.agents.get(agentPublicKey);
562
- const relayMessage = {
563
- type: "message",
564
- from: agentPublicKey,
565
- name: senderAgent?.name,
566
- envelope
567
- };
568
- const messageStr = JSON.stringify(relayMessage);
569
- for (const agent of this.agents.values()) {
570
- if (agent.publicKey !== agentPublicKey && agent.socket.readyState === WebSocket2.OPEN) {
571
- try {
572
- agent.socket.send(messageStr);
573
- } catch (err) {
574
- this.emit("error", err);
575
- }
576
- }
577
- }
578
- return;
579
- }
580
- if (msg.type === "ping") {
581
- socket.send(JSON.stringify({ type: "pong" }));
582
- return;
583
- }
584
- this.sendError(socket, `Unknown message type: ${msg.type}`);
585
- } catch (err) {
586
- this.emit("error", new Error(`Message parsing failed: ${err instanceof Error ? err.message : String(err)}`));
587
- this.sendError(socket, "Invalid message format");
588
- }
589
- });
590
- socket.on("close", () => {
591
- if (agentPublicKey) {
592
- const agent = this.agents.get(agentPublicKey);
593
- const agentName = agent?.name;
594
- this.agents.delete(agentPublicKey);
595
- this.emit("agent-disconnected", agentPublicKey);
596
- if (!this.storagePeers.includes(agentPublicKey)) {
597
- this.broadcastPeerEvent("peer_offline", agentPublicKey, agentName);
598
- }
599
- }
600
- });
601
- socket.on("error", (error) => {
602
- this.emit("error", error);
603
- });
604
- }
605
- /**
606
- * Send an error message to a client
607
- */
608
- sendError(socket, message) {
609
- try {
610
- if (socket.readyState === WebSocket2.OPEN) {
611
- socket.send(JSON.stringify({ type: "error", message }));
612
- }
613
- } catch (err) {
614
- this.emit("error", new Error(`Failed to send error message: ${err instanceof Error ? err.message : String(err)}`));
615
- }
616
- }
617
- /**
618
- * Broadcast a peer event to all connected agents
619
- */
620
- broadcastPeerEvent(eventType, publicKey, name) {
621
- const message = {
622
- type: eventType,
623
- publicKey,
624
- name
625
- };
626
- const messageStr = JSON.stringify(message);
627
- for (const agent of this.agents.values()) {
628
- if (agent.publicKey !== publicKey && agent.socket.readyState === WebSocket2.OPEN) {
629
- try {
630
- agent.socket.send(messageStr);
631
- } catch (err) {
632
- this.emit("error", new Error(`Failed to send ${eventType} event: ${err instanceof Error ? err.message : String(err)}`));
633
- }
634
- }
635
- }
636
- }
637
- /**
638
- * Handle peer list request from an agent
639
- */
640
- handlePeerListRequest(envelope, socket, requesterPublicKey) {
641
- if (!this.identity) {
642
- this.sendError(socket, "Relay does not support peer discovery (no identity configured)");
643
- return;
644
- }
645
- const { filters } = envelope.payload;
646
- const now = Date.now();
647
- let peers = Array.from(this.agents.values());
648
- peers = peers.filter((p) => p.publicKey !== requesterPublicKey);
649
- if (filters?.activeWithin) {
650
- peers = peers.filter((p) => now - p.lastSeen < filters.activeWithin);
651
- }
652
- if (filters?.limit && filters.limit > 0) {
653
- peers = peers.slice(0, filters.limit);
654
- }
655
- const response = {
656
- peers: peers.map((p) => ({
657
- publicKey: p.publicKey,
658
- metadata: p.name || p.metadata ? {
659
- name: p.name,
660
- version: p.metadata?.version,
661
- capabilities: p.metadata?.capabilities
662
- } : void 0,
663
- lastSeen: p.lastSeen
664
- })),
665
- totalPeers: this.agents.size - 1,
666
- // Exclude requester from count
667
- relayPublicKey: this.identity.publicKey
668
- };
669
- const responseEnvelope = createEnvelope(
670
- "peer_list_response",
671
- this.identity.publicKey,
672
- this.identity.privateKey,
673
- response,
674
- Date.now(),
675
- envelope.id
676
- // Reply to the request
677
- );
678
- const relayMessage = {
679
- type: "message",
680
- from: this.identity.publicKey,
681
- name: "relay",
682
- envelope: responseEnvelope
683
- };
684
- try {
685
- socket.send(JSON.stringify(relayMessage));
686
- } catch (err) {
687
- this.emit("error", new Error(`Failed to send peer list response: ${err instanceof Error ? err.message : String(err)}`));
688
- }
689
- }
690
- };
691
-
692
206
  // src/relay/client.ts
693
- import { EventEmitter as EventEmitter2 } from "events";
694
- import WebSocket3 from "ws";
695
- var RelayClient = class extends EventEmitter2 {
207
+ import { EventEmitter } from "events";
208
+ import WebSocket2 from "ws";
209
+ var RelayClient = class extends EventEmitter {
696
210
  ws = null;
697
211
  config;
698
212
  reconnectAttempts = 0;
@@ -714,7 +228,7 @@ var RelayClient = class extends EventEmitter2 {
714
228
  * Connect to the relay server
715
229
  */
716
230
  async connect() {
717
- if (this.ws && (this.ws.readyState === WebSocket3.CONNECTING || this.ws.readyState === WebSocket3.OPEN)) {
231
+ if (this.ws && (this.ws.readyState === WebSocket2.CONNECTING || this.ws.readyState === WebSocket2.OPEN)) {
718
232
  return;
719
233
  }
720
234
  this.shouldReconnect = true;
@@ -792,7 +306,7 @@ var RelayClient = class extends EventEmitter2 {
792
306
  async doConnect() {
793
307
  return new Promise((resolve, reject) => {
794
308
  try {
795
- this.ws = new WebSocket3(this.config.relayUrl);
309
+ this.ws = new WebSocket2(this.config.relayUrl);
796
310
  let resolved = false;
797
311
  const resolveOnce = (callback) => {
798
312
  if (!resolved) {
@@ -928,7 +442,7 @@ var RelayClient = class extends EventEmitter2 {
928
442
  startPingInterval() {
929
443
  this.stopPingInterval();
930
444
  this.pingInterval = setInterval(() => {
931
- if (this.ws && this.ws.readyState === WebSocket3.OPEN) {
445
+ if (this.ws && this.ws.readyState === WebSocket2.OPEN) {
932
446
  const ping = { type: "ping" };
933
447
  this.ws.send(JSON.stringify(ping));
934
448
  }
@@ -957,8 +471,8 @@ var RelayClient = class extends EventEmitter2 {
957
471
  };
958
472
 
959
473
  // src/discovery/peer-discovery.ts
960
- import { EventEmitter as EventEmitter3 } from "events";
961
- var PeerDiscoveryService = class extends EventEmitter3 {
474
+ import { EventEmitter as EventEmitter2 } from "events";
475
+ var PeerDiscoveryService = class extends EventEmitter2 {
962
476
  config;
963
477
  constructor(config) {
964
478
  super();
@@ -1211,7 +725,7 @@ function validateRevealRecord(record) {
1211
725
  }
1212
726
 
1213
727
  // src/reputation/store.ts
1214
- import { promises as fs2 } from "fs";
728
+ import { promises as fs } from "fs";
1215
729
  import { dirname } from "path";
1216
730
  var ReputationStore = class {
1217
731
  filePath;
@@ -1227,7 +741,7 @@ var ReputationStore = class {
1227
741
  */
1228
742
  async load() {
1229
743
  try {
1230
- const content = await fs2.readFile(this.filePath, "utf-8");
744
+ const content = await fs.readFile(this.filePath, "utf-8");
1231
745
  const lines = content.trim().split("\n").filter((line) => line.length > 0);
1232
746
  for (const line of lines) {
1233
747
  try {
@@ -1283,9 +797,9 @@ var ReputationStore = class {
1283
797
  * Append a record to the JSONL file
1284
798
  */
1285
799
  async appendToFile(record) {
1286
- await fs2.mkdir(dirname(this.filePath), { recursive: true });
800
+ await fs.mkdir(dirname(this.filePath), { recursive: true });
1287
801
  const line = JSON.stringify(record) + "\n";
1288
- await fs2.appendFile(this.filePath, line, "utf-8");
802
+ await fs.appendFile(this.filePath, line, "utf-8");
1289
803
  }
1290
804
  /**
1291
805
  * Add a verification record
@@ -1459,9 +973,9 @@ function verifyVerificationSignature(record) {
1459
973
  }
1460
974
 
1461
975
  // src/reputation/commit-reveal.ts
1462
- import { createHash as createHash2 } from "crypto";
976
+ import { createHash } from "crypto";
1463
977
  function hashPrediction(prediction) {
1464
- return createHash2("sha256").update(prediction).digest("hex");
978
+ return createHash("sha256").update(prediction).digest("hex");
1465
979
  }
1466
980
  function createCommit(agent, privateKey, domain, prediction, timestamp, expiryMs) {
1467
981
  const commitment = hashPrediction(prediction);
@@ -1550,7 +1064,7 @@ function verdictWeight(verdict) {
1550
1064
  return 0;
1551
1065
  }
1552
1066
  }
1553
- function computeTrustScore(agent, domain, verifications, currentTime) {
1067
+ function computeTrustScore(agent, domain, verifications, currentTime, options) {
1554
1068
  const relevantVerifications = verifications.filter(
1555
1069
  (v) => v.target === agent && v.domain === domain
1556
1070
  );
@@ -1564,17 +1078,34 @@ function computeTrustScore(agent, domain, verifications, currentTime) {
1564
1078
  topVerifiers: []
1565
1079
  };
1566
1080
  }
1081
+ const maxDepth = options?.maxDepth ?? 3;
1082
+ const visitedAgents = options?.visitedAgents;
1083
+ const getVerifierScore = options?.getVerifierScore;
1084
+ if (visitedAgents) {
1085
+ visitedAgents.add(agent);
1086
+ }
1567
1087
  let totalWeight = 0;
1568
1088
  const verifierWeights = /* @__PURE__ */ new Map();
1569
1089
  for (const verification of relevantVerifications) {
1570
1090
  const deltaTime = currentTime - verification.timestamp;
1571
1091
  const decayFactor = decay(deltaTime);
1572
1092
  const verdict = verdictWeight(verification.verdict);
1573
- const weight = verdict * verification.confidence * decayFactor;
1093
+ let verifierTrustWeight;
1094
+ if (!getVerifierScore || maxDepth <= 0) {
1095
+ verifierTrustWeight = 1;
1096
+ } else if (visitedAgents?.has(verification.verifier)) {
1097
+ verifierTrustWeight = 0.5;
1098
+ } else {
1099
+ verifierTrustWeight = getVerifierScore(verification.verifier, domain);
1100
+ }
1101
+ const weight = verdict * verification.confidence * decayFactor * verifierTrustWeight;
1574
1102
  totalWeight += weight;
1575
- const currentVerifierWeight = verifierWeights.get(verification.verifier) || 0;
1103
+ const currentVerifierWeight = verifierWeights.get(verification.verifier) ?? 0;
1576
1104
  verifierWeights.set(verification.verifier, currentVerifierWeight + Math.abs(weight));
1577
1105
  }
1106
+ if (visitedAgents) {
1107
+ visitedAgents.delete(agent);
1108
+ }
1578
1109
  const rawScore = totalWeight / Math.max(relevantVerifications.length, 1);
1579
1110
  const normalizedScore = Math.max(0, Math.min(1, (rawScore + 1) / 2));
1580
1111
  const lastVerified = Math.max(...relevantVerifications.map((v) => v.timestamp));
@@ -1602,23 +1133,12 @@ function computeTrustScores(agent, verifications, currentTime) {
1602
1133
  var computeAllTrustScores = computeTrustScores;
1603
1134
 
1604
1135
  export {
1605
- generateKeyPair,
1606
- signMessage,
1607
- verifySignature,
1608
- exportKeyPair,
1609
- importKeyPair,
1610
1136
  loadPeerConfig,
1611
1137
  savePeerConfig,
1612
1138
  initPeerConfig,
1613
- canonicalize,
1614
- computeId,
1615
- createEnvelope,
1616
- verifyEnvelope,
1617
1139
  sendToPeer,
1618
1140
  decodeInboundEnvelope,
1619
1141
  sendViaRelay,
1620
- MessageStore,
1621
- RelayServer,
1622
1142
  RelayClient,
1623
1143
  PeerDiscoveryService,
1624
1144
  DEFAULT_BOOTSTRAP_RELAYS,
@@ -1642,4 +1162,4 @@ export {
1642
1162
  computeTrustScores,
1643
1163
  computeAllTrustScores
1644
1164
  };
1645
- //# sourceMappingURL=chunk-JUOGKXFN.js.map
1165
+ //# sourceMappingURL=chunk-IOHECZYT.js.map