@rookdaemon/agora 0.2.7 → 0.2.9

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 (124) hide show
  1. package/README.md +33 -0
  2. package/dist/chunk-JUOGKXFN.js +1645 -0
  3. package/dist/chunk-JUOGKXFN.js.map +1 -0
  4. package/dist/cli.d.ts +0 -2
  5. package/dist/cli.js +1163 -1137
  6. package/dist/cli.js.map +1 -1
  7. package/dist/index.d.ts +1613 -25
  8. package/dist/index.js +1135 -24
  9. package/dist/index.js.map +1 -1
  10. package/package.json +11 -2
  11. package/dist/cli.d.ts.map +0 -1
  12. package/dist/config.d.ts +0 -59
  13. package/dist/config.d.ts.map +0 -1
  14. package/dist/config.js +0 -115
  15. package/dist/config.js.map +0 -1
  16. package/dist/discovery/bootstrap.d.ts +0 -32
  17. package/dist/discovery/bootstrap.d.ts.map +0 -1
  18. package/dist/discovery/bootstrap.js +0 -36
  19. package/dist/discovery/bootstrap.js.map +0 -1
  20. package/dist/discovery/peer-discovery.d.ts +0 -59
  21. package/dist/discovery/peer-discovery.d.ts.map +0 -1
  22. package/dist/discovery/peer-discovery.js +0 -108
  23. package/dist/discovery/peer-discovery.js.map +0 -1
  24. package/dist/identity/keypair.d.ts +0 -42
  25. package/dist/identity/keypair.d.ts.map +0 -1
  26. package/dist/identity/keypair.js +0 -83
  27. package/dist/identity/keypair.js.map +0 -1
  28. package/dist/index.d.ts.map +0 -1
  29. package/dist/message/envelope.d.ts +0 -59
  30. package/dist/message/envelope.d.ts.map +0 -1
  31. package/dist/message/envelope.js +0 -83
  32. package/dist/message/envelope.js.map +0 -1
  33. package/dist/message/types/paper-discovery.d.ts +0 -28
  34. package/dist/message/types/paper-discovery.d.ts.map +0 -1
  35. package/dist/message/types/paper-discovery.js +0 -2
  36. package/dist/message/types/paper-discovery.js.map +0 -1
  37. package/dist/message/types/peer-discovery.d.ts +0 -78
  38. package/dist/message/types/peer-discovery.d.ts.map +0 -1
  39. package/dist/message/types/peer-discovery.js +0 -90
  40. package/dist/message/types/peer-discovery.js.map +0 -1
  41. package/dist/peer/client.d.ts +0 -50
  42. package/dist/peer/client.d.ts.map +0 -1
  43. package/dist/peer/client.js +0 -138
  44. package/dist/peer/client.js.map +0 -1
  45. package/dist/peer/manager.d.ts +0 -65
  46. package/dist/peer/manager.d.ts.map +0 -1
  47. package/dist/peer/manager.js +0 -153
  48. package/dist/peer/manager.js.map +0 -1
  49. package/dist/peer/server.d.ts +0 -65
  50. package/dist/peer/server.d.ts.map +0 -1
  51. package/dist/peer/server.js +0 -154
  52. package/dist/peer/server.js.map +0 -1
  53. package/dist/registry/capability.d.ts +0 -44
  54. package/dist/registry/capability.d.ts.map +0 -1
  55. package/dist/registry/capability.js +0 -94
  56. package/dist/registry/capability.js.map +0 -1
  57. package/dist/registry/discovery-service.d.ts +0 -64
  58. package/dist/registry/discovery-service.d.ts.map +0 -1
  59. package/dist/registry/discovery-service.js +0 -129
  60. package/dist/registry/discovery-service.js.map +0 -1
  61. package/dist/registry/messages.d.ts +0 -105
  62. package/dist/registry/messages.d.ts.map +0 -1
  63. package/dist/registry/messages.js +0 -2
  64. package/dist/registry/messages.js.map +0 -1
  65. package/dist/registry/peer-store.d.ts +0 -57
  66. package/dist/registry/peer-store.d.ts.map +0 -1
  67. package/dist/registry/peer-store.js +0 -92
  68. package/dist/registry/peer-store.js.map +0 -1
  69. package/dist/registry/peer.d.ts +0 -20
  70. package/dist/registry/peer.d.ts.map +0 -1
  71. package/dist/registry/peer.js +0 -2
  72. package/dist/registry/peer.js.map +0 -1
  73. package/dist/relay/client.d.ts +0 -112
  74. package/dist/relay/client.d.ts.map +0 -1
  75. package/dist/relay/client.js +0 -281
  76. package/dist/relay/client.js.map +0 -1
  77. package/dist/relay/server.d.ts +0 -76
  78. package/dist/relay/server.d.ts.map +0 -1
  79. package/dist/relay/server.js +0 -338
  80. package/dist/relay/server.js.map +0 -1
  81. package/dist/relay/types.d.ts +0 -35
  82. package/dist/relay/types.d.ts.map +0 -1
  83. package/dist/relay/types.js +0 -2
  84. package/dist/relay/types.js.map +0 -1
  85. package/dist/reputation/commit-reveal.d.ts +0 -45
  86. package/dist/reputation/commit-reveal.d.ts.map +0 -1
  87. package/dist/reputation/commit-reveal.js +0 -125
  88. package/dist/reputation/commit-reveal.js.map +0 -1
  89. package/dist/reputation/scoring.d.ts +0 -31
  90. package/dist/reputation/scoring.d.ts.map +0 -1
  91. package/dist/reputation/scoring.js +0 -105
  92. package/dist/reputation/scoring.js.map +0 -1
  93. package/dist/reputation/store.d.ts +0 -83
  94. package/dist/reputation/store.d.ts.map +0 -1
  95. package/dist/reputation/store.js +0 -202
  96. package/dist/reputation/store.js.map +0 -1
  97. package/dist/reputation/types.d.ts +0 -150
  98. package/dist/reputation/types.d.ts.map +0 -1
  99. package/dist/reputation/types.js +0 -113
  100. package/dist/reputation/types.js.map +0 -1
  101. package/dist/reputation/verification.d.ts +0 -28
  102. package/dist/reputation/verification.d.ts.map +0 -1
  103. package/dist/reputation/verification.js +0 -91
  104. package/dist/reputation/verification.js.map +0 -1
  105. package/dist/service.d.ts +0 -90
  106. package/dist/service.d.ts.map +0 -1
  107. package/dist/service.js +0 -176
  108. package/dist/service.js.map +0 -1
  109. package/dist/transport/http.d.ts +0 -41
  110. package/dist/transport/http.d.ts.map +0 -1
  111. package/dist/transport/http.js +0 -103
  112. package/dist/transport/http.js.map +0 -1
  113. package/dist/transport/peer-config.d.ts +0 -38
  114. package/dist/transport/peer-config.d.ts.map +0 -1
  115. package/dist/transport/peer-config.js +0 -41
  116. package/dist/transport/peer-config.js.map +0 -1
  117. package/dist/transport/relay.d.ts +0 -30
  118. package/dist/transport/relay.d.ts.map +0 -1
  119. package/dist/transport/relay.js +0 -85
  120. package/dist/transport/relay.js.map +0 -1
  121. package/dist/utils.d.ts +0 -40
  122. package/dist/utils.d.ts.map +0 -1
  123. package/dist/utils.js +0 -59
  124. package/dist/utils.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,25 +1,1613 @@
1
- export * from './identity/keypair.js';
2
- export * from './message/envelope.js';
3
- export * from './registry/capability.js';
4
- export * from './registry/peer.js';
5
- export * from './registry/peer-store.js';
6
- export * from './registry/messages.js';
7
- export * from './registry/discovery-service.js';
8
- export * from './message/types/paper-discovery.js';
9
- export * from './message/types/peer-discovery.js';
10
- export * from './transport/http.js';
11
- export * from './transport/peer-config.js';
12
- export * from './config.js';
13
- export * from './relay/server.js';
14
- export * from './relay/client.js';
15
- export * from './relay/types.js';
16
- export * from './utils.js';
17
- export * from './service.js';
18
- export * from './discovery/peer-discovery.js';
19
- export * from './discovery/bootstrap.js';
20
- export * from './reputation/types.js';
21
- export * from './reputation/verification.js';
22
- export * from './reputation/commit-reveal.js';
23
- export * from './reputation/scoring.js';
24
- export * from './reputation/store.js';
25
- //# sourceMappingURL=index.d.ts.map
1
+ import { EventEmitter } from 'node:events';
2
+ import { WebSocket } from 'ws';
3
+ import { Request, Response, NextFunction, Router } from 'express';
4
+ import http from 'node:http';
5
+
6
+ /**
7
+ * Represents an ed25519 key pair for agent identity
8
+ */
9
+ interface KeyPair {
10
+ publicKey: string;
11
+ privateKey: string;
12
+ }
13
+ /**
14
+ * Generates a new ed25519 key pair
15
+ * @returns KeyPair with hex-encoded public and private keys
16
+ */
17
+ declare function generateKeyPair(): KeyPair;
18
+ /**
19
+ * Signs a message with the private key
20
+ * @param message - The message to sign (string or Buffer)
21
+ * @param privateKeyHex - The private key in hex format
22
+ * @returns Signature as hex string
23
+ */
24
+ declare function signMessage(message: string | Buffer, privateKeyHex: string): string;
25
+ /**
26
+ * Verifies a signature with the public key
27
+ * @param message - The original message (string or Buffer)
28
+ * @param signatureHex - The signature in hex format
29
+ * @param publicKeyHex - The public key in hex format
30
+ * @returns true if signature is valid, false otherwise
31
+ */
32
+ declare function verifySignature(message: string | Buffer, signatureHex: string, publicKeyHex: string): boolean;
33
+ /**
34
+ * Exports a key pair to a JSON-serializable format
35
+ * @param keyPair - The key pair to export
36
+ * @returns KeyPair object with hex-encoded keys
37
+ */
38
+ declare function exportKeyPair(keyPair: KeyPair): KeyPair;
39
+ /**
40
+ * Imports a key pair from hex strings
41
+ * @param publicKeyHex - The public key in hex format
42
+ * @param privateKeyHex - The private key in hex format
43
+ * @returns KeyPair object
44
+ * @throws Error if keys are not valid hex strings
45
+ */
46
+ declare function importKeyPair(publicKeyHex: string, privateKeyHex: string): KeyPair;
47
+
48
+ /**
49
+ * Message types on the Agora network.
50
+ * Every piece of data flowing between agents is wrapped in an envelope.
51
+ */
52
+ type MessageType = 'announce' | 'discover' | 'request' | 'response' | 'publish' | 'subscribe' | 'verify' | 'ack' | 'error' | 'paper_discovery' | 'peer_list_request' | 'peer_list_response' | 'peer_referral' | 'capability_announce' | 'capability_query' | 'capability_response' | 'commit' | 'reveal' | 'verification' | 'revocation' | 'reputation_query' | 'reputation_response';
53
+ /**
54
+ * The signed envelope that wraps every message on the network.
55
+ * Content-addressed: the ID is the hash of the canonical payload.
56
+ * Signed: every envelope carries a signature from the sender's private key.
57
+ */
58
+ interface Envelope<T = unknown> {
59
+ /** Content-addressed ID: SHA-256 hash of canonical payload */
60
+ id: string;
61
+ /** Message type */
62
+ type: MessageType;
63
+ /** Sender's public key (hex-encoded ed25519) */
64
+ sender: string;
65
+ /** Unix timestamp (ms) when the message was created */
66
+ timestamp: number;
67
+ /** Optional: ID of the message this is responding to */
68
+ inReplyTo?: string;
69
+ /** The actual payload */
70
+ payload: T;
71
+ /** ed25519 signature over the canonical form (hex-encoded) */
72
+ signature: string;
73
+ }
74
+ /**
75
+ * Canonical form of an envelope for signing/hashing.
76
+ * Deterministic JSON serialization: recursively sorted keys, no whitespace.
77
+ */
78
+ declare function canonicalize(type: MessageType, sender: string, timestamp: number, payload: unknown, inReplyTo?: string): string;
79
+ /**
80
+ * Compute the content-addressed ID for a message.
81
+ */
82
+ declare function computeId(canonical: string): string;
83
+ /**
84
+ * Create a signed envelope.
85
+ * @param type - Message type
86
+ * @param sender - Sender's public key (hex)
87
+ * @param privateKey - Sender's private key (hex) for signing
88
+ * @param payload - The message payload
89
+ * @param timestamp - Timestamp for the envelope (ms), defaults to Date.now()
90
+ * @param inReplyTo - Optional ID of the message being replied to
91
+ * @returns A signed Envelope
92
+ */
93
+ declare function createEnvelope<T>(type: MessageType, sender: string, privateKey: string, payload: T, timestamp?: number, inReplyTo?: string): Envelope<T>;
94
+ /**
95
+ * Verify an envelope's integrity and authenticity.
96
+ * Checks:
97
+ * 1. Canonical form matches the ID (content-addressing)
98
+ * 2. Signature is valid for the sender's public key
99
+ *
100
+ * @returns Object with `valid` boolean and optional `reason` for failure
101
+ */
102
+ declare function verifyEnvelope(envelope: Envelope): {
103
+ valid: boolean;
104
+ reason?: string;
105
+ };
106
+
107
+ /**
108
+ * A capability describes something an agent can do
109
+ */
110
+ interface Capability {
111
+ /** Unique ID (content-addressed hash of name + version + schema) */
112
+ id: string;
113
+ /** Human-readable name: 'code-review', 'summarization', 'translation' */
114
+ name: string;
115
+ /** Semantic version */
116
+ version: string;
117
+ /** What the capability does */
118
+ description: string;
119
+ /** JSON Schema for expected input */
120
+ inputSchema?: object;
121
+ /** JSON Schema for expected output */
122
+ outputSchema?: object;
123
+ /** Discovery tags: ['code', 'typescript', 'review'] */
124
+ tags: string[];
125
+ }
126
+ /**
127
+ * Creates a capability with a content-addressed ID.
128
+ *
129
+ * @param name - Human-readable capability name
130
+ * @param version - Semantic version string
131
+ * @param description - Description of what the capability does
132
+ * @param options - Optional input/output schemas and tags
133
+ * @returns A Capability object with computed ID
134
+ */
135
+ declare function createCapability(name: string, version: string, description: string, options?: {
136
+ inputSchema?: object;
137
+ outputSchema?: object;
138
+ tags?: string[];
139
+ }): Capability;
140
+ /**
141
+ * Validates that a capability has all required fields.
142
+ *
143
+ * @param capability - The capability to validate
144
+ * @returns Object with `valid` boolean and optional `errors` array
145
+ */
146
+ declare function validateCapability(capability: unknown): {
147
+ valid: boolean;
148
+ errors?: string[];
149
+ };
150
+
151
+ /**
152
+ * A peer is an agent on the network
153
+ */
154
+ interface Peer {
155
+ /** Identity (hex-encoded ed25519 public key) */
156
+ publicKey: string;
157
+ /** Capabilities this peer offers */
158
+ capabilities: Capability[];
159
+ /** Unix timestamp (ms) when this peer was last seen */
160
+ lastSeen: number;
161
+ /** Optional metadata about the peer */
162
+ metadata?: {
163
+ /** Human-readable alias */
164
+ name?: string;
165
+ /** Agent software version */
166
+ version?: string;
167
+ };
168
+ }
169
+
170
+ /**
171
+ * In-memory store for known peers on the network
172
+ */
173
+ declare class PeerStore {
174
+ private peers;
175
+ /**
176
+ * Add or update a peer in the store.
177
+ * If a peer with the same publicKey exists, it will be updated.
178
+ *
179
+ * @param peer - The peer to add or update
180
+ */
181
+ addOrUpdatePeer(peer: Peer): void;
182
+ /**
183
+ * Remove a peer from the store.
184
+ *
185
+ * @param publicKey - The public key of the peer to remove
186
+ * @returns true if the peer was removed, false if it didn't exist
187
+ */
188
+ removePeer(publicKey: string): boolean;
189
+ /**
190
+ * Get a peer by their public key.
191
+ *
192
+ * @param publicKey - The public key of the peer to retrieve
193
+ * @returns The peer if found, undefined otherwise
194
+ */
195
+ getPeer(publicKey: string): Peer | undefined;
196
+ /**
197
+ * Find all peers that offer a specific capability by name.
198
+ *
199
+ * @param name - The capability name to search for
200
+ * @returns Array of peers that have a capability with the given name
201
+ */
202
+ findByCapability(name: string): Peer[];
203
+ /**
204
+ * Find all peers that have capabilities with a specific tag.
205
+ *
206
+ * @param tag - The tag to search for
207
+ * @returns Array of peers that have at least one capability with the given tag
208
+ */
209
+ findByTag(tag: string): Peer[];
210
+ /**
211
+ * Get all peers in the store.
212
+ *
213
+ * @returns Array of all peers
214
+ */
215
+ allPeers(): Peer[];
216
+ /**
217
+ * Remove peers that haven't been seen within the specified time window.
218
+ *
219
+ * @param maxAgeMs - Maximum age in milliseconds. Peers older than this will be removed.
220
+ * @param currentTime - Current timestamp (ms), defaults to Date.now()
221
+ * @returns Number of peers removed
222
+ */
223
+ prune(maxAgeMs: number, currentTime?: number): number;
224
+ }
225
+
226
+ /**
227
+ * Payload for 'announce' messages.
228
+ * An agent publishes its capabilities and metadata to the network.
229
+ */
230
+ interface AnnouncePayload {
231
+ /** Capabilities this agent offers */
232
+ capabilities: Capability[];
233
+ /** Optional metadata about the agent */
234
+ metadata?: {
235
+ /** Human-readable agent name */
236
+ name?: string;
237
+ /** Agent software version */
238
+ version?: string;
239
+ };
240
+ }
241
+ /**
242
+ * Payload for 'discover' messages.
243
+ * An agent queries the network to find peers with specific capabilities.
244
+ */
245
+ interface DiscoverPayload {
246
+ /** Query parameters for discovery */
247
+ query: {
248
+ /** Filter by capability name */
249
+ capabilityName?: string;
250
+ /** Filter by capability tag */
251
+ tag?: string;
252
+ };
253
+ }
254
+ /**
255
+ * Payload for responses to 'discover' messages.
256
+ * Returns a list of peers matching the discovery query.
257
+ */
258
+ interface DiscoverResponsePayload {
259
+ /** Peers matching the discovery query */
260
+ peers: Array<{
261
+ /** Public key of the peer */
262
+ publicKey: string;
263
+ /** Capabilities the peer offers */
264
+ capabilities: Capability[];
265
+ /** Optional metadata about the peer */
266
+ metadata?: {
267
+ /** Human-readable peer name */
268
+ name?: string;
269
+ /** Peer software version */
270
+ version?: string;
271
+ };
272
+ }>;
273
+ }
274
+ /**
275
+ * Payload for 'capability_announce' messages.
276
+ * An agent publishes its capabilities to the network.
277
+ */
278
+ interface CapabilityAnnouncePayload {
279
+ /** Agent's Ed25519 public key */
280
+ publicKey: string;
281
+ /** List of capabilities offered */
282
+ capabilities: Capability[];
283
+ /** Optional metadata */
284
+ metadata?: {
285
+ name?: string;
286
+ version?: string;
287
+ lastSeen?: number;
288
+ };
289
+ }
290
+ /**
291
+ * Payload for 'capability_query' messages.
292
+ * An agent queries the network for peers with specific capabilities.
293
+ */
294
+ interface CapabilityQueryPayload {
295
+ /** Query type: by name, tag, or schema */
296
+ queryType: 'name' | 'tag' | 'schema';
297
+ /** Query value (capability name, tag, or JSON schema) */
298
+ query: string | object;
299
+ /** Optional filters */
300
+ filters?: {
301
+ /** Minimum trust score (RFC-001 integration) */
302
+ minTrustScore?: number;
303
+ /** Maximum results to return */
304
+ limit?: number;
305
+ };
306
+ }
307
+ /**
308
+ * Payload for 'capability_response' messages.
309
+ * Response to a capability_query with matching peers.
310
+ */
311
+ interface CapabilityResponsePayload {
312
+ /** Query ID this is responding to */
313
+ queryId: string;
314
+ /** Matching peers */
315
+ peers: Array<{
316
+ publicKey: string;
317
+ capabilities: Capability[];
318
+ metadata?: {
319
+ name?: string;
320
+ version?: string;
321
+ lastSeen?: number;
322
+ };
323
+ /** Trust score from RFC-001 (Phase 2b) */
324
+ trustScore?: number;
325
+ }>;
326
+ /** Total matching peers (may be > peers.length if limited) */
327
+ totalMatches: number;
328
+ }
329
+
330
+ /**
331
+ * DiscoveryService manages capability-based peer discovery.
332
+ * It maintains a local index of peer capabilities and handles
333
+ * capability announce, query, and response messages.
334
+ */
335
+ declare class DiscoveryService {
336
+ private peerStore;
337
+ private identity;
338
+ constructor(peerStore: PeerStore, identity: {
339
+ publicKey: string;
340
+ privateKey: string;
341
+ });
342
+ /**
343
+ * Announce own capabilities to the network.
344
+ * Creates a capability_announce envelope that can be broadcast to peers.
345
+ *
346
+ * @param capabilities - List of capabilities this agent offers
347
+ * @param metadata - Optional metadata about this agent
348
+ * @returns A signed capability_announce envelope
349
+ */
350
+ announce(capabilities: Capability[], metadata?: {
351
+ name?: string;
352
+ version?: string;
353
+ }): Envelope<CapabilityAnnouncePayload>;
354
+ /**
355
+ * Handle an incoming capability_announce message.
356
+ * Updates the peer store with the announced capabilities.
357
+ *
358
+ * @param envelope - The capability_announce envelope to process
359
+ */
360
+ handleAnnounce(envelope: Envelope<CapabilityAnnouncePayload>): void;
361
+ /**
362
+ * Create a capability query payload.
363
+ *
364
+ * @param queryType - Type of query: 'name', 'tag', or 'schema'
365
+ * @param query - The query value (capability name, tag, or schema)
366
+ * @param filters - Optional filters (limit, minTrustScore)
367
+ * @returns A capability_query payload
368
+ */
369
+ query(queryType: 'name' | 'tag' | 'schema', query: string | object, filters?: {
370
+ limit?: number;
371
+ minTrustScore?: number;
372
+ }): CapabilityQueryPayload;
373
+ /**
374
+ * Handle an incoming capability_query message.
375
+ * Searches the local peer store and returns matching peers.
376
+ *
377
+ * @param envelope - The capability_query envelope to process
378
+ * @returns A capability_response envelope with matching peers
379
+ */
380
+ handleQuery(envelope: Envelope<CapabilityQueryPayload>): Envelope<CapabilityResponsePayload>;
381
+ /**
382
+ * Remove peers that haven't been seen within the specified time window.
383
+ *
384
+ * @param maxAgeMs - Maximum age in milliseconds
385
+ * @returns Number of peers removed
386
+ */
387
+ pruneStale(maxAgeMs: number, currentTime?: number): number;
388
+ }
389
+
390
+ /**
391
+ * Payload for 'paper_discovery' messages.
392
+ * An agent publishes a discovered academic paper to the network.
393
+ * Each paper gets its own envelope for easy referencing and threading.
394
+ */
395
+ interface PaperDiscoveryPayload {
396
+ /** arXiv identifier (e.g. "2501.12345") */
397
+ arxiv_id: string;
398
+ /** Paper title */
399
+ title: string;
400
+ /** List of author names */
401
+ authors: string[];
402
+ /** Key contribution in 1-2 sentences */
403
+ claim: string;
404
+ /** Confidence score (0-1) in the relevance/importance assessment */
405
+ confidence: number;
406
+ /** Tags describing relevance domains */
407
+ relevance_tags: string[];
408
+ /** Agent ID of the discoverer */
409
+ discoverer: string;
410
+ /** ISO 8601 timestamp of discovery */
411
+ timestamp: string;
412
+ /** URL to the abstract page */
413
+ abstract_url: string;
414
+ /** URL to the PDF (optional) */
415
+ pdf_url?: string;
416
+ }
417
+
418
+ /**
419
+ * Peer discovery message types for the Agora network.
420
+ */
421
+ /**
422
+ * Request peer list from relay
423
+ */
424
+ interface PeerListRequestPayload {
425
+ /** Optional filters */
426
+ filters?: {
427
+ /** Only peers seen in last N ms */
428
+ activeWithin?: number;
429
+ /** Maximum peers to return */
430
+ limit?: number;
431
+ };
432
+ }
433
+ /**
434
+ * Relay responds with connected peers
435
+ */
436
+ interface PeerListResponsePayload {
437
+ /** List of known peers */
438
+ peers: Array<{
439
+ /** Peer's Ed25519 public key */
440
+ publicKey: string;
441
+ /** Optional metadata (if peer announced) */
442
+ metadata?: {
443
+ name?: string;
444
+ version?: string;
445
+ capabilities?: string[];
446
+ };
447
+ /** Last seen timestamp (ms) */
448
+ lastSeen: number;
449
+ }>;
450
+ /** Total peer count (may be > peers.length if limited) */
451
+ totalPeers: number;
452
+ /** Relay's public key (for trust verification) */
453
+ relayPublicKey: string;
454
+ }
455
+ /**
456
+ * Agent recommends another agent
457
+ */
458
+ interface PeerReferralPayload {
459
+ /** Referred peer's public key */
460
+ publicKey: string;
461
+ /** Optional endpoint (if known) */
462
+ endpoint?: string;
463
+ /** Optional metadata */
464
+ metadata?: {
465
+ name?: string;
466
+ version?: string;
467
+ capabilities?: string[];
468
+ };
469
+ /** Referrer's comment */
470
+ comment?: string;
471
+ /** Trust hint (RFC-001 integration) */
472
+ trustScore?: number;
473
+ }
474
+ /**
475
+ * Validate PeerListRequestPayload
476
+ */
477
+ declare function validatePeerListRequest(payload: unknown): {
478
+ valid: boolean;
479
+ errors: string[];
480
+ };
481
+ /**
482
+ * Validate PeerListResponsePayload
483
+ */
484
+ declare function validatePeerListResponse(payload: unknown): {
485
+ valid: boolean;
486
+ errors: string[];
487
+ };
488
+ /**
489
+ * Validate PeerReferralPayload
490
+ */
491
+ declare function validatePeerReferral(payload: unknown): {
492
+ valid: boolean;
493
+ errors: string[];
494
+ };
495
+
496
+ interface PeerConfig {
497
+ /** Peer's webhook URL, e.g. http://localhost:18790/hooks (undefined for relay-only peers) */
498
+ url?: string;
499
+ /** Peer's webhook auth token (undefined for relay-only peers) */
500
+ token?: string;
501
+ /** Peer's public key (hex) for verifying responses */
502
+ publicKey: string;
503
+ }
504
+ interface TransportConfig {
505
+ /** This agent's keypair */
506
+ identity: {
507
+ publicKey: string;
508
+ privateKey: string;
509
+ };
510
+ /** Known peers */
511
+ peers: Map<string, PeerConfig>;
512
+ }
513
+ /**
514
+ * Send a signed envelope to a peer via HTTP webhook.
515
+ * Creates the envelope, signs it, and POSTs to the peer's /hooks/agent endpoint.
516
+ * Returns the HTTP status code.
517
+ */
518
+ declare function sendToPeer(config: TransportConfig, peerPublicKey: string, type: MessageType, payload: unknown, inReplyTo?: string): Promise<{
519
+ ok: boolean;
520
+ status: number;
521
+ error?: string;
522
+ }>;
523
+ /**
524
+ * Decode and verify an inbound Agora envelope from a webhook message.
525
+ * Expects the message to start with [AGORA_ENVELOPE] followed by base64.
526
+ * Returns the verified envelope or an error.
527
+ */
528
+ declare function decodeInboundEnvelope(message: string, knownPeers: Map<string, PeerConfig>): {
529
+ ok: true;
530
+ envelope: Envelope;
531
+ } | {
532
+ ok: false;
533
+ reason: string;
534
+ };
535
+
536
+ interface PeerConfigFile {
537
+ identity: {
538
+ publicKey: string;
539
+ privateKey: string;
540
+ name?: string;
541
+ };
542
+ relay?: string | {
543
+ url: string;
544
+ name?: string;
545
+ };
546
+ peers: Record<string, {
547
+ url?: string;
548
+ token?: string;
549
+ publicKey: string;
550
+ name?: string;
551
+ }>;
552
+ }
553
+ /**
554
+ * Load peer configuration from a JSON file.
555
+ * @param path - Path to the config file
556
+ * @returns The parsed configuration
557
+ * @throws Error if file doesn't exist or contains invalid JSON
558
+ */
559
+ declare function loadPeerConfig(path: string): PeerConfigFile;
560
+ /**
561
+ * Save peer configuration to a JSON file.
562
+ * @param path - Path to the config file
563
+ * @param config - The configuration to save
564
+ */
565
+ declare function savePeerConfig(path: string, config: PeerConfigFile): void;
566
+ /**
567
+ * Initialize peer configuration, generating a new keypair if the file doesn't exist.
568
+ * If the file exists, loads and returns it.
569
+ * @param path - Path to the config file
570
+ * @returns The configuration (loaded or newly created)
571
+ */
572
+ declare function initPeerConfig(path: string): PeerConfigFile;
573
+
574
+ /**
575
+ * Normalized relay configuration (supports both string and object in config file).
576
+ */
577
+ interface RelayConfig {
578
+ url: string;
579
+ autoConnect: boolean;
580
+ name?: string;
581
+ reconnectMaxMs?: number;
582
+ }
583
+ /**
584
+ * Peer entry in config (webhook URL, token, public key).
585
+ */
586
+ interface AgoraPeerConfig {
587
+ publicKey: string;
588
+ /** Webhook URL (undefined for relay-only peers) */
589
+ url?: string;
590
+ /** Webhook auth token (undefined for relay-only peers) */
591
+ token?: string;
592
+ name?: string;
593
+ }
594
+ /**
595
+ * Identity with optional display name (e.g. for relay registration).
596
+ */
597
+ interface AgoraIdentity {
598
+ publicKey: string;
599
+ privateKey: string;
600
+ name?: string;
601
+ }
602
+ /**
603
+ * Canonical Agora configuration shape.
604
+ * Use loadAgoraConfig() to load from file with normalized relay.
605
+ */
606
+ interface AgoraConfig {
607
+ identity: AgoraIdentity;
608
+ peers: Record<string, AgoraPeerConfig>;
609
+ relay?: RelayConfig;
610
+ }
611
+ /**
612
+ * Default config file path: AGORA_CONFIG env or ~/.config/agora/config.json
613
+ */
614
+ declare function getDefaultConfigPath(): string;
615
+ /**
616
+ * Load and normalize Agora configuration from a JSON file (sync).
617
+ * Supports relay as string (backward compat) or object { url?, autoConnect?, name?, reconnectMaxMs? }.
618
+ *
619
+ * @param path - Config file path; defaults to getDefaultConfigPath()
620
+ * @returns Normalized AgoraConfig
621
+ * @throws Error if file doesn't exist or config is invalid
622
+ */
623
+ declare function loadAgoraConfig(path?: string): AgoraConfig;
624
+ /**
625
+ * Load and normalize Agora configuration from a JSON file (async).
626
+ *
627
+ * @param path - Config file path; defaults to getDefaultConfigPath()
628
+ * @returns Normalized AgoraConfig
629
+ * @throws Error if file doesn't exist or config is invalid
630
+ */
631
+ declare function loadAgoraConfigAsync(path?: string): Promise<AgoraConfig>;
632
+
633
+ /**
634
+ * Represents a connected agent in the relay
635
+ */
636
+ interface ConnectedAgent {
637
+ /** Agent's public key */
638
+ publicKey: string;
639
+ /** Optional agent name */
640
+ name?: string;
641
+ /** WebSocket connection */
642
+ socket: WebSocket;
643
+ /** Last seen timestamp (ms) */
644
+ lastSeen: number;
645
+ /** Optional metadata */
646
+ metadata?: {
647
+ version?: string;
648
+ capabilities?: string[];
649
+ };
650
+ }
651
+ /**
652
+ * Events emitted by RelayServer
653
+ */
654
+ interface RelayServerEvents {
655
+ 'agent-registered': (publicKey: string) => void;
656
+ 'agent-disconnected': (publicKey: string) => void;
657
+ 'message-relayed': (from: string, to: string, envelope: Envelope) => void;
658
+ 'error': (error: Error) => void;
659
+ }
660
+ /**
661
+ * WebSocket relay server for routing messages between agents.
662
+ *
663
+ * Agents connect to the relay and register with their public key.
664
+ * Messages are routed to recipients based on the 'to' field.
665
+ * All envelopes are verified before being forwarded.
666
+ */
667
+ interface RelayServerOptions {
668
+ /** Optional relay identity for peer_list_request handling */
669
+ identity?: {
670
+ publicKey: string;
671
+ privateKey: string;
672
+ };
673
+ /** Public keys that should have messages stored when offline */
674
+ storagePeers?: string[];
675
+ /** Directory for persisting messages for storage peers */
676
+ storageDir?: string;
677
+ }
678
+ declare class RelayServer extends EventEmitter {
679
+ private wss;
680
+ private agents;
681
+ private identity?;
682
+ private storagePeers;
683
+ private store;
684
+ constructor(options?: {
685
+ publicKey: string;
686
+ privateKey: string;
687
+ } | RelayServerOptions);
688
+ /**
689
+ * Start the relay server
690
+ * @param port - Port to listen on
691
+ * @param host - Optional host (default: all interfaces)
692
+ */
693
+ start(port: number, host?: string): Promise<void>;
694
+ /**
695
+ * Stop the relay server
696
+ */
697
+ stop(): Promise<void>;
698
+ /**
699
+ * Get all connected agents
700
+ */
701
+ getAgents(): Map<string, ConnectedAgent>;
702
+ /**
703
+ * Handle incoming connection
704
+ */
705
+ private handleConnection;
706
+ /**
707
+ * Send an error message to a client
708
+ */
709
+ private sendError;
710
+ /**
711
+ * Broadcast a peer event to all connected agents
712
+ */
713
+ private broadcastPeerEvent;
714
+ /**
715
+ * Handle peer list request from an agent
716
+ */
717
+ private handlePeerListRequest;
718
+ }
719
+
720
+ /**
721
+ * Messages sent from client to relay server
722
+ */
723
+ interface RelayClientMessage {
724
+ type: 'register' | 'message' | 'broadcast' | 'ping';
725
+ publicKey?: string;
726
+ name?: string;
727
+ to?: string;
728
+ envelope?: Envelope;
729
+ }
730
+ /**
731
+ * Messages received from relay server
732
+ */
733
+ interface RelayServerMessage {
734
+ type: 'registered' | 'message' | 'error' | 'pong' | 'peer_online' | 'peer_offline';
735
+ publicKey?: string;
736
+ name?: string;
737
+ from?: string;
738
+ envelope?: Envelope;
739
+ peers?: Array<{
740
+ publicKey: string;
741
+ name?: string;
742
+ }>;
743
+ code?: string;
744
+ message?: string;
745
+ }
746
+ /**
747
+ * Peer presence information
748
+ */
749
+ interface RelayPeer {
750
+ publicKey: string;
751
+ name?: string;
752
+ }
753
+
754
+ /**
755
+ * Configuration for RelayClient
756
+ */
757
+ interface RelayClientConfig {
758
+ /** WebSocket URL of the relay server */
759
+ relayUrl: string;
760
+ /** Agent's public key */
761
+ publicKey: string;
762
+ /** Agent's private key (for signing) */
763
+ privateKey: string;
764
+ /** Optional name for this agent */
765
+ name?: string;
766
+ /** Keepalive ping interval in milliseconds (default: 30000) */
767
+ pingInterval?: number;
768
+ /** Maximum reconnection delay in milliseconds (default: 60000) */
769
+ maxReconnectDelay?: number;
770
+ }
771
+ /**
772
+ * Events emitted by RelayClient
773
+ */
774
+ interface RelayClientEvents {
775
+ /** Emitted when successfully connected and registered */
776
+ 'connected': () => void;
777
+ /** Emitted when disconnected from relay */
778
+ 'disconnected': () => void;
779
+ /** Emitted when a verified message is received */
780
+ 'message': (envelope: Envelope, from: string, fromName?: string) => void;
781
+ /** Emitted when a peer comes online */
782
+ 'peer_online': (peer: RelayPeer) => void;
783
+ /** Emitted when a peer goes offline */
784
+ 'peer_offline': (peer: RelayPeer) => void;
785
+ /** Emitted on errors */
786
+ 'error': (error: Error) => void;
787
+ }
788
+ /**
789
+ * Persistent WebSocket client for the Agora relay server.
790
+ * Maintains a long-lived connection, handles reconnection, and routes messages.
791
+ */
792
+ declare class RelayClient extends EventEmitter {
793
+ private ws;
794
+ private config;
795
+ private reconnectAttempts;
796
+ private reconnectTimeout;
797
+ private pingInterval;
798
+ private isConnected;
799
+ private isRegistered;
800
+ private shouldReconnect;
801
+ private onlinePeers;
802
+ constructor(config: RelayClientConfig);
803
+ /**
804
+ * Connect to the relay server
805
+ */
806
+ connect(): Promise<void>;
807
+ /**
808
+ * Disconnect from the relay server
809
+ */
810
+ disconnect(): void;
811
+ /**
812
+ * Check if currently connected and registered
813
+ */
814
+ connected(): boolean;
815
+ /**
816
+ * Send a message to a specific peer
817
+ */
818
+ send(to: string, envelope: Envelope): Promise<{
819
+ ok: boolean;
820
+ error?: string;
821
+ }>;
822
+ /**
823
+ * Broadcast a message to all connected peers
824
+ */
825
+ broadcast(envelope: Envelope): Promise<{
826
+ ok: boolean;
827
+ error?: string;
828
+ }>;
829
+ /**
830
+ * Get list of currently online peers
831
+ */
832
+ getOnlinePeers(): RelayPeer[];
833
+ /**
834
+ * Check if a specific peer is online
835
+ */
836
+ isPeerOnline(publicKey: string): boolean;
837
+ /**
838
+ * Internal: Perform connection
839
+ */
840
+ private doConnect;
841
+ /**
842
+ * Handle incoming message from relay
843
+ */
844
+ private handleMessage;
845
+ /**
846
+ * Schedule reconnection with exponential backoff
847
+ */
848
+ private scheduleReconnect;
849
+ /**
850
+ * Start periodic ping messages
851
+ */
852
+ private startPingInterval;
853
+ /**
854
+ * Stop ping interval
855
+ */
856
+ private stopPingInterval;
857
+ /**
858
+ * Cleanup resources
859
+ */
860
+ private cleanup;
861
+ }
862
+
863
+ /**
864
+ * message-buffer.ts — In-memory bounded message queue per agent.
865
+ *
866
+ * When messages are delivered to an agent via the relay, they are also
867
+ * stored here so that HTTP polling clients can retrieve them via GET /v1/messages.
868
+ */
869
+ interface BufferedMessage {
870
+ id: string;
871
+ from: string;
872
+ fromName?: string;
873
+ type: string;
874
+ payload: unknown;
875
+ timestamp: number;
876
+ inReplyTo?: string;
877
+ }
878
+ /**
879
+ * MessageBuffer stores inbound messages per agent public key.
880
+ * FIFO eviction when the buffer is full (max 100 messages).
881
+ */
882
+ declare class MessageBuffer {
883
+ private buffers;
884
+ /**
885
+ * Add a message to an agent's buffer.
886
+ * Evicts the oldest message if the buffer is full.
887
+ */
888
+ add(publicKey: string, message: BufferedMessage): void;
889
+ /**
890
+ * Retrieve messages for an agent, optionally filtering by `since` timestamp.
891
+ * Returns messages with timestamp > since (exclusive).
892
+ */
893
+ get(publicKey: string, since?: number): BufferedMessage[];
894
+ /**
895
+ * Clear all messages for an agent (after polling without `since`).
896
+ */
897
+ clear(publicKey: string): void;
898
+ /**
899
+ * Remove all state for a disconnected agent.
900
+ */
901
+ delete(publicKey: string): void;
902
+ }
903
+
904
+ /**
905
+ * store.ts — File-based message store for offline peers.
906
+ * When the relay has storage enabled for certain public keys, messages
907
+ * for offline recipients are persisted and delivered when they connect.
908
+ */
909
+ interface StoredMessage {
910
+ from: string;
911
+ name?: string;
912
+ envelope: object;
913
+ }
914
+ declare class MessageStore {
915
+ private storageDir;
916
+ constructor(storageDir: string);
917
+ private recipientDir;
918
+ save(recipientKey: string, message: StoredMessage): void;
919
+ load(recipientKey: string): StoredMessage[];
920
+ clear(recipientKey: string): void;
921
+ }
922
+
923
+ /**
924
+ * jwt-auth.ts — JWT token creation and validation middleware.
925
+ *
926
+ * Tokens are signed with AGORA_RELAY_JWT_SECRET (required env var).
927
+ * Expiry defaults to 3600 seconds (1 hour), configurable via AGORA_JWT_EXPIRY_SECONDS.
928
+ *
929
+ * Token payload: { publicKey, name }
930
+ */
931
+
932
+ interface JwtPayload {
933
+ publicKey: string;
934
+ name?: string;
935
+ }
936
+ /**
937
+ * Augment Express Request to carry decoded JWT payload.
938
+ */
939
+ interface AuthenticatedRequest extends Request {
940
+ agent?: JwtPayload;
941
+ }
942
+ /**
943
+ * Create a signed JWT for a registered agent.
944
+ * Returns the token string and its expiry timestamp (ms since epoch).
945
+ */
946
+ declare function createToken(payload: JwtPayload): {
947
+ token: string;
948
+ expiresAt: number;
949
+ };
950
+ /**
951
+ * Revoke a token by its jti claim so it cannot be used again.
952
+ * The revocation entry is stored with the token's expiry so it can be
953
+ * pruned automatically once the token would no longer be valid anyway.
954
+ */
955
+ declare function revokeToken(token: string): void;
956
+ /**
957
+ * Express middleware that validates the Authorization: Bearer <token> header.
958
+ * Attaches decoded payload to `req.agent` on success.
959
+ * Responds with 401 if missing/invalid/expired/revoked.
960
+ */
961
+ declare function requireAuth(req: AuthenticatedRequest, res: Response, next: NextFunction): void;
962
+
963
+ /**
964
+ * rest-api.ts — Express router implementing the Agora relay REST API.
965
+ *
966
+ * Endpoints:
967
+ * POST /v1/register — Register agent, obtain JWT session token
968
+ * POST /v1/send — Send message to a peer (requires auth)
969
+ * GET /v1/peers — List online peers (requires auth)
970
+ * GET /v1/messages — Poll for new inbound messages (requires auth)
971
+ * DELETE /v1/disconnect — Invalidate token and disconnect (requires auth)
972
+ */
973
+
974
+ /**
975
+ * A session for a REST-connected agent.
976
+ * privateKey is held only in memory and never logged or persisted.
977
+ */
978
+ interface RestSession {
979
+ publicKey: string;
980
+ privateKey: string;
981
+ name?: string;
982
+ metadata?: {
983
+ version?: string;
984
+ capabilities?: string[];
985
+ };
986
+ registeredAt: number;
987
+ expiresAt: number;
988
+ token: string;
989
+ }
990
+ /**
991
+ * Minimal interface for the relay server that the REST API depends on.
992
+ */
993
+ interface RelayInterface {
994
+ getAgents(): Map<string, {
995
+ publicKey: string;
996
+ name?: string;
997
+ lastSeen: number;
998
+ metadata?: {
999
+ version?: string;
1000
+ capabilities?: string[];
1001
+ };
1002
+ socket: unknown;
1003
+ }>;
1004
+ on(event: 'message-relayed', handler: (from: string, to: string, envelope: unknown) => void): void;
1005
+ }
1006
+ /**
1007
+ * Envelope creation function interface (matches createEnvelope from message/envelope).
1008
+ */
1009
+ type CreateEnvelopeFn = (type: string, sender: string, privateKey: string, payload: unknown, timestamp?: number, inReplyTo?: string) => {
1010
+ id: string;
1011
+ type: string;
1012
+ sender: string;
1013
+ timestamp: number;
1014
+ payload: unknown;
1015
+ signature: string;
1016
+ inReplyTo?: string;
1017
+ };
1018
+ /**
1019
+ * Envelope verification function interface.
1020
+ */
1021
+ type VerifyEnvelopeFn = (envelope: unknown) => {
1022
+ valid: boolean;
1023
+ reason?: string;
1024
+ };
1025
+ /**
1026
+ * Create the REST API router.
1027
+ */
1028
+ declare function createRestRouter(relay: RelayInterface, buffer: MessageBuffer, sessions: Map<string, RestSession>, createEnv: CreateEnvelopeFn, verifyEnv: VerifyEnvelopeFn): Router;
1029
+
1030
+ /**
1031
+ * run-relay.ts — Start Agora relay: WebSocket server and optional REST API.
1032
+ *
1033
+ * When REST is enabled, starts:
1034
+ * 1. WebSocket relay (RelayServer) on wsPort
1035
+ * 2. REST API server (Express) on restPort (default wsPort + 1)
1036
+ *
1037
+ * Environment variables (when REST enabled):
1038
+ * AGORA_RELAY_JWT_SECRET — Required for REST (JWT signing)
1039
+ * AGORA_JWT_EXPIRY_SECONDS — JWT expiry in seconds (default: 3600)
1040
+ * PORT — WebSocket port (default: 3001); REST uses PORT+1
1041
+ */
1042
+
1043
+ interface RunRelayOptions {
1044
+ /** WebSocket port (default from PORT env or 3001) */
1045
+ wsPort?: number;
1046
+ /** REST API port (default: wsPort + 1). Ignored if enableRest is false. */
1047
+ restPort?: number;
1048
+ /** Enable REST API (requires AGORA_RELAY_JWT_SECRET). Default: true if AGORA_RELAY_JWT_SECRET is set. */
1049
+ enableRest?: boolean;
1050
+ /** Relay server options (identity, storagePeers, storageDir) */
1051
+ relayOptions?: RelayServerOptions;
1052
+ }
1053
+ /**
1054
+ * Start WebSocket relay and optionally REST API.
1055
+ * Returns { relay, httpServer } where httpServer is set only when REST is enabled.
1056
+ */
1057
+ declare function runRelay(options?: RunRelayOptions): Promise<{
1058
+ relay: RelayServer;
1059
+ httpServer?: http.Server;
1060
+ }>;
1061
+
1062
+ /**
1063
+ * Get a short display version of a public key using the last 8 characters.
1064
+ * Ed25519 public keys all share the same OID prefix, so the last 8 characters
1065
+ * are more distinguishable than the first 8.
1066
+ *
1067
+ * @param publicKey - The full public key hex string
1068
+ * @returns "..." followed by the last 8 characters of the key
1069
+ */
1070
+ declare function shortKey(publicKey: string): string;
1071
+ /**
1072
+ * Resolves the name to broadcast when connecting to a relay.
1073
+ * Priority order:
1074
+ * 1. CLI --name flag
1075
+ * 2. config.relay.name (if relay is an object with name property)
1076
+ * 3. config.identity.name
1077
+ * 4. undefined (no name broadcast)
1078
+ *
1079
+ * @param config - The Agora configuration (or compatible config with identity and optional relay)
1080
+ * @param cliName - Optional name from CLI --name flag
1081
+ * @returns The resolved name to broadcast, or undefined if none available
1082
+ */
1083
+ declare function resolveBroadcastName(config: {
1084
+ identity: {
1085
+ name?: string;
1086
+ };
1087
+ relay?: {
1088
+ name?: string;
1089
+ } | string;
1090
+ }, cliName?: string): string | undefined;
1091
+ /**
1092
+ * Formats a display name with short ID postfix.
1093
+ * If name exists: "name (...3f8c2247)"
1094
+ * If no name: "...3f8c2247" (short ID only)
1095
+ *
1096
+ * @param name - Optional name to display (should not be a short ID)
1097
+ * @param publicKey - The public key to use for short ID
1098
+ * @returns Formatted display string
1099
+ */
1100
+ declare function formatDisplayName(name: string | undefined, publicKey: string): string;
1101
+
1102
+ /**
1103
+ * Service config: identity, peers keyed by name, optional relay.
1104
+ */
1105
+ interface AgoraServiceConfig {
1106
+ identity: AgoraIdentity;
1107
+ peers: Map<string, PeerConfig>;
1108
+ relay?: RelayConfig;
1109
+ }
1110
+ interface SendMessageOptions {
1111
+ peerName: string;
1112
+ type: MessageType;
1113
+ payload: unknown;
1114
+ inReplyTo?: string;
1115
+ }
1116
+ interface SendMessageResult {
1117
+ ok: boolean;
1118
+ status: number;
1119
+ error?: string;
1120
+ }
1121
+ interface DecodeInboundResult {
1122
+ ok: boolean;
1123
+ envelope?: Envelope;
1124
+ reason?: string;
1125
+ }
1126
+ type RelayMessageHandler = (envelope: Envelope) => void;
1127
+ type RelayMessageHandlerWithName = (envelope: Envelope, from: string, fromName?: string) => void;
1128
+ interface Logger {
1129
+ debug(message: string): void;
1130
+ }
1131
+ interface RelayClientLike {
1132
+ connect(): Promise<void>;
1133
+ disconnect(): void;
1134
+ connected(): boolean;
1135
+ send(to: string, envelope: Envelope): Promise<{
1136
+ ok: boolean;
1137
+ error?: string;
1138
+ }>;
1139
+ on(event: 'message', handler: (envelope: Envelope, from: string, fromName?: string) => void): void;
1140
+ on(event: 'error', handler: (error: Error) => void): void;
1141
+ }
1142
+ interface RelayClientFactory {
1143
+ (opts: {
1144
+ relayUrl: string;
1145
+ publicKey: string;
1146
+ privateKey: string;
1147
+ name?: string;
1148
+ pingInterval: number;
1149
+ maxReconnectDelay: number;
1150
+ }): RelayClientLike;
1151
+ }
1152
+ /**
1153
+ * High-level Agora service: send by peer name, decode inbound, relay lifecycle.
1154
+ */
1155
+ declare class AgoraService {
1156
+ private config;
1157
+ private relayClient;
1158
+ private relayMessageHandler;
1159
+ private relayMessageHandlerWithName;
1160
+ private logger;
1161
+ private relayClientFactory;
1162
+ constructor(config: AgoraServiceConfig, logger?: Logger, relayClientFactory?: RelayClientFactory);
1163
+ /**
1164
+ * Send a signed message to a named peer.
1165
+ * Tries HTTP webhook first; falls back to relay if HTTP is unavailable.
1166
+ */
1167
+ sendMessage(options: SendMessageOptions): Promise<SendMessageResult>;
1168
+ /**
1169
+ * Decode and verify an inbound envelope from a webhook message.
1170
+ */
1171
+ decodeInbound(message: string): Promise<DecodeInboundResult>;
1172
+ getPeers(): string[];
1173
+ getPeerConfig(name: string): PeerConfig | undefined;
1174
+ /**
1175
+ * Connect to the relay server.
1176
+ */
1177
+ connectRelay(url: string): Promise<void>;
1178
+ setRelayMessageHandler(handler: RelayMessageHandler): void;
1179
+ setRelayMessageHandlerWithName(handler: RelayMessageHandlerWithName): void;
1180
+ disconnectRelay(): Promise<void>;
1181
+ isRelayConnected(): boolean;
1182
+ /**
1183
+ * Load Agora configuration and return service config (peers as Map).
1184
+ */
1185
+ static loadConfig(path?: string): Promise<AgoraServiceConfig>;
1186
+ }
1187
+
1188
+ /**
1189
+ * Configuration for PeerDiscoveryService
1190
+ */
1191
+ interface PeerDiscoveryConfig {
1192
+ /** Agent's public key */
1193
+ publicKey: string;
1194
+ /** Agent's private key for signing */
1195
+ privateKey: string;
1196
+ /** RelayClient instance for communication */
1197
+ relayClient: RelayClient;
1198
+ /** Public key of the relay server (for sending peer list requests) */
1199
+ relayPublicKey?: string;
1200
+ }
1201
+ /**
1202
+ * Events emitted by PeerDiscoveryService
1203
+ */
1204
+ interface PeerDiscoveryEvents {
1205
+ /** Emitted when peers are discovered */
1206
+ 'peers-discovered': (peers: PeerListResponsePayload['peers']) => void;
1207
+ /** Emitted when a peer referral is received */
1208
+ 'peer-referral': (referral: PeerReferralPayload, from: string) => void;
1209
+ /** Emitted on errors */
1210
+ 'error': (error: Error) => void;
1211
+ }
1212
+ /**
1213
+ * Service for discovering peers on the Agora network
1214
+ */
1215
+ declare class PeerDiscoveryService extends EventEmitter {
1216
+ private config;
1217
+ constructor(config: PeerDiscoveryConfig);
1218
+ /**
1219
+ * Request peer list from relay
1220
+ */
1221
+ discoverViaRelay(filters?: PeerListRequestPayload['filters']): Promise<PeerListResponsePayload | null>;
1222
+ /**
1223
+ * Send peer referral to another agent
1224
+ */
1225
+ referPeer(recipientPublicKey: string, referredPublicKey: string, metadata?: {
1226
+ name?: string;
1227
+ endpoint?: string;
1228
+ comment?: string;
1229
+ trustScore?: number;
1230
+ }): Promise<{
1231
+ ok: boolean;
1232
+ error?: string;
1233
+ }>;
1234
+ /**
1235
+ * Handle incoming peer referral
1236
+ */
1237
+ private handleReferral;
1238
+ /**
1239
+ * Handle incoming peer list from relay
1240
+ */
1241
+ private handlePeerList;
1242
+ }
1243
+
1244
+ /**
1245
+ * Bootstrap configuration for peer discovery on the Agora network.
1246
+ * Provides default bootstrap relays for initial network entry.
1247
+ */
1248
+ /**
1249
+ * Default bootstrap relay servers
1250
+ * These are well-known relays that serve as initial entry points to the network
1251
+ */
1252
+ declare const DEFAULT_BOOTSTRAP_RELAYS: {
1253
+ url: string;
1254
+ name: string;
1255
+ }[];
1256
+ /**
1257
+ * Configuration for bootstrap connection
1258
+ */
1259
+ interface BootstrapConfig {
1260
+ /** Bootstrap relay URL */
1261
+ relayUrl: string;
1262
+ /** Optional relay public key (for verification) */
1263
+ relayPublicKey?: string;
1264
+ /** Connection timeout in ms (default: 10000) */
1265
+ timeout?: number;
1266
+ }
1267
+ /**
1268
+ * Get default bootstrap relay configuration
1269
+ */
1270
+ declare function getDefaultBootstrapRelay(): BootstrapConfig;
1271
+ /**
1272
+ * Parse bootstrap relay URL and optional public key
1273
+ */
1274
+ declare function parseBootstrapRelay(url: string, publicKey?: string): BootstrapConfig;
1275
+
1276
+ /**
1277
+ * Core data structures for the Agora reputation layer.
1278
+ * Phase 1: Verification records, commit-reveal patterns, and trust scoring.
1279
+ */
1280
+ /**
1281
+ * A cryptographically signed verification of another agent's output or claim.
1282
+ * Core primitive for building computational reputation.
1283
+ */
1284
+ interface VerificationRecord {
1285
+ /** Content-addressed ID (hash of canonical JSON) */
1286
+ id: string;
1287
+ /** Public key of verifying agent */
1288
+ verifier: string;
1289
+ /** ID of message/output being verified */
1290
+ target: string;
1291
+ /** Capability domain (e.g., 'ocr', 'summarization', 'code_review') */
1292
+ domain: string;
1293
+ /** Verification verdict */
1294
+ verdict: 'correct' | 'incorrect' | 'disputed';
1295
+ /** Verifier's confidence in their check (0-1) */
1296
+ confidence: number;
1297
+ /** Optional link to independent verification data */
1298
+ evidence?: string;
1299
+ /** Unix timestamp (ms) */
1300
+ timestamp: number;
1301
+ /** Ed25519 signature over canonical JSON */
1302
+ signature: string;
1303
+ }
1304
+ /**
1305
+ * A commitment to a prediction before outcome is known.
1306
+ * Prevents post-hoc editing of predictions.
1307
+ */
1308
+ interface CommitRecord {
1309
+ /** Content-addressed ID */
1310
+ id: string;
1311
+ /** Public key of committing agent */
1312
+ agent: string;
1313
+ /** Domain of prediction */
1314
+ domain: string;
1315
+ /** SHA-256 hash of prediction string */
1316
+ commitment: string;
1317
+ /** Unix timestamp (ms) */
1318
+ timestamp: number;
1319
+ /** Expiry time (ms) - commitment invalid after this */
1320
+ expiry: number;
1321
+ /** Ed25519 signature */
1322
+ signature: string;
1323
+ }
1324
+ /**
1325
+ * Reveals the prediction and outcome after commitment expiry.
1326
+ * Enables verification of prediction accuracy.
1327
+ */
1328
+ interface RevealRecord {
1329
+ /** Content-addressed ID */
1330
+ id: string;
1331
+ /** Public key of revealing agent */
1332
+ agent: string;
1333
+ /** ID of original commit message */
1334
+ commitmentId: string;
1335
+ /** Original prediction (plaintext) */
1336
+ prediction: string;
1337
+ /** Observed outcome */
1338
+ outcome: string;
1339
+ /** Evidence for outcome (optional) */
1340
+ evidence?: string;
1341
+ /** Unix timestamp (ms) */
1342
+ timestamp: number;
1343
+ /** Ed25519 signature */
1344
+ signature: string;
1345
+ }
1346
+ /**
1347
+ * Computed reputation score for an agent in a specific domain.
1348
+ * Derived from verification history, not stored directly.
1349
+ */
1350
+ interface TrustScore {
1351
+ /** Public key of agent being scored */
1352
+ agent: string;
1353
+ /** Domain of reputation */
1354
+ domain: string;
1355
+ /** Computed score (0-1, where 1 = highest trust) */
1356
+ score: number;
1357
+ /** Number of verifications considered */
1358
+ verificationCount: number;
1359
+ /** Timestamp of most recent verification (ms) */
1360
+ lastVerified: number;
1361
+ /** Public keys of top verifiers (by weight) */
1362
+ topVerifiers: string[];
1363
+ }
1364
+ /**
1365
+ * Request for reputation data about a specific agent.
1366
+ */
1367
+ interface ReputationQuery {
1368
+ /** Public key of agent being queried */
1369
+ agent: string;
1370
+ /** Optional: filter by capability domain */
1371
+ domain?: string;
1372
+ /** Optional: only include verifications after this timestamp */
1373
+ after?: number;
1374
+ }
1375
+ /**
1376
+ * Response containing reputation data for a queried agent.
1377
+ */
1378
+ interface ReputationResponse {
1379
+ /** Public key of agent being reported on */
1380
+ agent: string;
1381
+ /** Domain filter (if requested) */
1382
+ domain?: string;
1383
+ /** Verification records matching the query */
1384
+ verifications: VerificationRecord[];
1385
+ /** Computed trust scores by domain */
1386
+ scores: Record<string, TrustScore>;
1387
+ }
1388
+ /**
1389
+ * Revocation of a previously issued verification.
1390
+ * Used when a verifier discovers their verification was incorrect.
1391
+ */
1392
+ interface RevocationRecord {
1393
+ /** Content-addressed ID of this revocation */
1394
+ id: string;
1395
+ /** Public key of agent revoking (must match original verifier) */
1396
+ verifier: string;
1397
+ /** ID of verification being revoked */
1398
+ verificationId: string;
1399
+ /** Reason for revocation */
1400
+ reason: string;
1401
+ /** Unix timestamp (ms) */
1402
+ timestamp: number;
1403
+ /** Ed25519 signature */
1404
+ signature: string;
1405
+ }
1406
+ /**
1407
+ * Validation result structure
1408
+ */
1409
+ interface ValidationResult {
1410
+ valid: boolean;
1411
+ errors: string[];
1412
+ }
1413
+ /**
1414
+ * Validate a verification record structure
1415
+ */
1416
+ declare function validateVerificationRecord(record: unknown): ValidationResult;
1417
+ /**
1418
+ * Validate a commit record structure
1419
+ */
1420
+ declare function validateCommitRecord(record: unknown): ValidationResult;
1421
+ /**
1422
+ * Validate a reveal record structure
1423
+ */
1424
+ declare function validateRevealRecord(record: unknown): ValidationResult;
1425
+
1426
+ /**
1427
+ * Verification record creation and validation.
1428
+ * Core primitive for computational reputation.
1429
+ */
1430
+
1431
+ /**
1432
+ * Create a signed verification record
1433
+ * @param verifier - Public key of the verifying agent
1434
+ * @param privateKey - Private key for signing
1435
+ * @param target - ID of the message/output being verified
1436
+ * @param domain - Capability domain
1437
+ * @param verdict - Verification verdict
1438
+ * @param confidence - Verifier's confidence (0-1)
1439
+ * @param timestamp - Timestamp for the verification (ms)
1440
+ * @param evidence - Optional link to verification evidence
1441
+ * @returns Signed VerificationRecord
1442
+ */
1443
+ declare function createVerification(verifier: string, privateKey: string, target: string, domain: string, verdict: 'correct' | 'incorrect' | 'disputed', confidence: number, timestamp: number, evidence?: string): VerificationRecord;
1444
+ /**
1445
+ * Verify the cryptographic signature of a verification record
1446
+ * @param record - The verification record to verify
1447
+ * @returns Object with valid flag and optional reason for failure
1448
+ */
1449
+ declare function verifyVerificationSignature(record: VerificationRecord): {
1450
+ valid: boolean;
1451
+ reason?: string;
1452
+ };
1453
+
1454
+ /**
1455
+ * Commit-reveal pattern implementation for tamper-proof predictions.
1456
+ * Agents commit to predictions before outcomes are known, then reveal after.
1457
+ */
1458
+
1459
+ /**
1460
+ * Create a commitment hash for a prediction
1461
+ * @param prediction - The prediction string
1462
+ * @returns SHA-256 hash of the prediction (hex string)
1463
+ */
1464
+ declare function hashPrediction(prediction: string): string;
1465
+ /**
1466
+ * Create a signed commit record
1467
+ * @param agent - Public key of the committing agent
1468
+ * @param privateKey - Private key for signing
1469
+ * @param domain - Domain of the prediction
1470
+ * @param prediction - The prediction to commit to
1471
+ * @param timestamp - Timestamp for the commit (ms)
1472
+ * @param expiryMs - Expiry time in milliseconds from timestamp
1473
+ * @returns Signed CommitRecord
1474
+ */
1475
+ declare function createCommit(agent: string, privateKey: string, domain: string, prediction: string, timestamp: number, expiryMs: number): CommitRecord;
1476
+ /**
1477
+ * Create a signed reveal record
1478
+ * @param agent - Public key of the revealing agent
1479
+ * @param privateKey - Private key for signing
1480
+ * @param commitmentId - ID of the original commit record
1481
+ * @param prediction - The original prediction (plaintext)
1482
+ * @param outcome - The observed outcome
1483
+ * @param timestamp - Timestamp for the reveal (ms)
1484
+ * @param evidence - Optional evidence for the outcome
1485
+ * @returns Signed RevealRecord
1486
+ */
1487
+ declare function createReveal(agent: string, privateKey: string, commitmentId: string, prediction: string, outcome: string, timestamp: number, evidence?: string): RevealRecord;
1488
+ /**
1489
+ * Verify a reveal against its commitment
1490
+ * @param commit - The original commit record
1491
+ * @param reveal - The reveal record
1492
+ * @returns Object with valid flag and optional reason for failure
1493
+ */
1494
+ declare function verifyReveal(commit: CommitRecord, reveal: RevealRecord): {
1495
+ valid: boolean;
1496
+ reason?: string;
1497
+ };
1498
+
1499
+ /**
1500
+ * Trust score computation with exponential time decay.
1501
+ * Domain-specific reputation scoring from verification history.
1502
+ */
1503
+
1504
+ /**
1505
+ * Exponential decay function for time-based reputation degradation.
1506
+ * @param deltaTimeMs - Time since verification (milliseconds)
1507
+ * @param lambda - Decay rate (default: ln(2)/70 ≈ 0.0099, giving 70-day half-life)
1508
+ * @returns Weight multiplier (0-1)
1509
+ */
1510
+ declare function decay(deltaTimeMs: number, lambda?: number): number;
1511
+ /**
1512
+ * Compute trust score for an agent in a specific domain
1513
+ * @param agent - Public key of the agent being scored
1514
+ * @param domain - Capability domain
1515
+ * @param verifications - All verification records (will be filtered by target and domain)
1516
+ * @param currentTime - Current timestamp (ms)
1517
+ * @returns TrustScore object with computed reputation
1518
+ */
1519
+ declare function computeTrustScore(agent: string, domain: string, verifications: VerificationRecord[], currentTime: number): TrustScore;
1520
+ /**
1521
+ * Compute trust scores for an agent across multiple domains
1522
+ * @param agent - Public key of the agent being scored
1523
+ * @param verifications - All verification records
1524
+ * @param currentTime - Current timestamp (ms)
1525
+ * @returns Map of domain to TrustScore
1526
+ */
1527
+ declare function computeTrustScores(agent: string, verifications: VerificationRecord[], currentTime: number): Map<string, TrustScore>;
1528
+ declare const computeAllTrustScores: typeof computeTrustScores;
1529
+
1530
+ /**
1531
+ * Local reputation store using JSONL append-only log.
1532
+ * Stores verification records, commits, and reveals.
1533
+ */
1534
+
1535
+ /**
1536
+ * Reputation store with JSONL persistence
1537
+ */
1538
+ declare class ReputationStore {
1539
+ private filePath;
1540
+ private verifications;
1541
+ private commits;
1542
+ private reveals;
1543
+ private loaded;
1544
+ constructor(filePath: string);
1545
+ /**
1546
+ * Load records from JSONL file
1547
+ */
1548
+ load(): Promise<void>;
1549
+ /**
1550
+ * Ensure the store is loaded
1551
+ */
1552
+ private ensureLoaded;
1553
+ /**
1554
+ * Append a record to the JSONL file
1555
+ */
1556
+ private appendToFile;
1557
+ /**
1558
+ * Add a verification record
1559
+ */
1560
+ addVerification(verification: VerificationRecord): Promise<void>;
1561
+ /**
1562
+ * Add a commit record
1563
+ */
1564
+ addCommit(commit: CommitRecord): Promise<void>;
1565
+ /**
1566
+ * Add a reveal record
1567
+ */
1568
+ addReveal(reveal: RevealRecord): Promise<void>;
1569
+ /**
1570
+ * Get all verifications
1571
+ */
1572
+ getVerifications(): Promise<VerificationRecord[]>;
1573
+ /**
1574
+ * Get verifications for a specific target
1575
+ */
1576
+ getVerificationsByTarget(target: string): Promise<VerificationRecord[]>;
1577
+ /**
1578
+ * Get verifications by domain
1579
+ */
1580
+ getVerificationsByDomain(domain: string): Promise<VerificationRecord[]>;
1581
+ /**
1582
+ * Get verifications for an agent (where they are the target of verification)
1583
+ * This requires looking up the target message to find the agent
1584
+ * For now, we'll return all verifications and let the caller filter
1585
+ */
1586
+ getVerificationsByDomainForAgent(domain: string): Promise<VerificationRecord[]>;
1587
+ /**
1588
+ * Get all commits
1589
+ */
1590
+ getCommits(): Promise<CommitRecord[]>;
1591
+ /**
1592
+ * Get commit by ID
1593
+ */
1594
+ getCommit(id: string): Promise<CommitRecord | null>;
1595
+ /**
1596
+ * Get commits by agent
1597
+ */
1598
+ getCommitsByAgent(agent: string): Promise<CommitRecord[]>;
1599
+ /**
1600
+ * Get all reveals
1601
+ */
1602
+ getReveals(): Promise<RevealRecord[]>;
1603
+ /**
1604
+ * Get reveal by commitment ID
1605
+ */
1606
+ getRevealByCommitment(commitmentId: string): Promise<RevealRecord | null>;
1607
+ /**
1608
+ * Get reveals by agent
1609
+ */
1610
+ getRevealsByAgent(agent: string): Promise<RevealRecord[]>;
1611
+ }
1612
+
1613
+ export { type AgoraConfig, type AgoraIdentity, type AgoraPeerConfig, AgoraService, type AgoraServiceConfig, type AnnouncePayload, type AuthenticatedRequest, type BootstrapConfig, type BufferedMessage, type Capability, type CapabilityAnnouncePayload, type CapabilityQueryPayload, type CapabilityResponsePayload, type CommitRecord, type CreateEnvelopeFn, DEFAULT_BOOTSTRAP_RELAYS, type DecodeInboundResult, type DiscoverPayload, type DiscoverResponsePayload, DiscoveryService, type Envelope, type JwtPayload, type KeyPair, type Logger, MessageBuffer, MessageStore, type MessageType, type PaperDiscoveryPayload, type Peer, type PeerConfig, type PeerConfigFile, type PeerDiscoveryConfig, type PeerDiscoveryEvents, PeerDiscoveryService, type PeerListRequestPayload, type PeerListResponsePayload, type PeerReferralPayload, PeerStore, RelayClient, type RelayClientConfig, type RelayClientEvents, type RelayClientFactory, type RelayClientLike, type RelayClientMessage, type RelayConfig, type RelayInterface, type RelayMessageHandler, type RelayMessageHandlerWithName, type RelayPeer, RelayServer, type RelayServerEvents, type RelayServerMessage, type RelayServerOptions, type ReputationQuery, type ReputationResponse, ReputationStore, type RestSession, type RevealRecord, type RevocationRecord, type RunRelayOptions, type SendMessageOptions, type SendMessageResult, type StoredMessage, type TransportConfig, type TrustScore, type ValidationResult, type VerificationRecord, type VerifyEnvelopeFn, canonicalize, computeAllTrustScores, computeId, computeTrustScore, computeTrustScores, createCapability, createCommit, createEnvelope, createRestRouter, createReveal, createToken, createVerification, decay, decodeInboundEnvelope, exportKeyPair, formatDisplayName, generateKeyPair, getDefaultBootstrapRelay, getDefaultConfigPath, hashPrediction, importKeyPair, initPeerConfig, loadAgoraConfig, loadAgoraConfigAsync, loadPeerConfig, parseBootstrapRelay, requireAuth, resolveBroadcastName, revokeToken, runRelay, savePeerConfig, sendToPeer, shortKey, signMessage, validateCapability, validateCommitRecord, validatePeerListRequest, validatePeerListResponse, validatePeerReferral, validateRevealRecord, validateVerificationRecord, verifyEnvelope, verifyReveal, verifySignature, verifyVerificationSignature };