agent-inbox 0.0.1 → 0.1.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.
Files changed (126) hide show
  1. package/CLAUDE.md +113 -0
  2. package/README.md +195 -1
  3. package/dist/federation/address.d.ts +24 -0
  4. package/dist/federation/address.d.ts.map +1 -0
  5. package/dist/federation/address.js +54 -0
  6. package/dist/federation/address.js.map +1 -0
  7. package/dist/federation/connection-manager.d.ts +118 -0
  8. package/dist/federation/connection-manager.d.ts.map +1 -0
  9. package/dist/federation/connection-manager.js +369 -0
  10. package/dist/federation/connection-manager.js.map +1 -0
  11. package/dist/federation/delivery-queue.d.ts +66 -0
  12. package/dist/federation/delivery-queue.d.ts.map +1 -0
  13. package/dist/federation/delivery-queue.js +199 -0
  14. package/dist/federation/delivery-queue.js.map +1 -0
  15. package/dist/federation/index.d.ts +7 -0
  16. package/dist/federation/index.d.ts.map +1 -0
  17. package/dist/federation/index.js +6 -0
  18. package/dist/federation/index.js.map +1 -0
  19. package/dist/federation/routing-engine.d.ts +74 -0
  20. package/dist/federation/routing-engine.d.ts.map +1 -0
  21. package/dist/federation/routing-engine.js +158 -0
  22. package/dist/federation/routing-engine.js.map +1 -0
  23. package/dist/federation/trust.d.ts +39 -0
  24. package/dist/federation/trust.d.ts.map +1 -0
  25. package/dist/federation/trust.js +64 -0
  26. package/dist/federation/trust.js.map +1 -0
  27. package/dist/index.d.ts +60 -2
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +217 -18
  30. package/dist/index.js.map +1 -1
  31. package/dist/ipc/ipc-server.d.ts +20 -0
  32. package/dist/ipc/ipc-server.d.ts.map +1 -0
  33. package/dist/ipc/ipc-server.js +152 -0
  34. package/dist/ipc/ipc-server.js.map +1 -0
  35. package/dist/jsonrpc/mail-server.d.ts +45 -0
  36. package/dist/jsonrpc/mail-server.d.ts.map +1 -0
  37. package/dist/jsonrpc/mail-server.js +284 -0
  38. package/dist/jsonrpc/mail-server.js.map +1 -0
  39. package/dist/map/map-client.d.ts +91 -0
  40. package/dist/map/map-client.d.ts.map +1 -0
  41. package/dist/map/map-client.js +202 -0
  42. package/dist/map/map-client.js.map +1 -0
  43. package/dist/mcp/mcp-server.d.ts +23 -0
  44. package/dist/mcp/mcp-server.d.ts.map +1 -0
  45. package/dist/mcp/mcp-server.js +226 -0
  46. package/dist/mcp/mcp-server.js.map +1 -0
  47. package/dist/push/notifier.d.ts +49 -0
  48. package/dist/push/notifier.d.ts.map +1 -0
  49. package/dist/push/notifier.js +150 -0
  50. package/dist/push/notifier.js.map +1 -0
  51. package/dist/registry/warm-registry.d.ts +63 -0
  52. package/dist/registry/warm-registry.d.ts.map +1 -0
  53. package/dist/registry/warm-registry.js +173 -0
  54. package/dist/registry/warm-registry.js.map +1 -0
  55. package/dist/router/message-router.d.ts +44 -0
  56. package/dist/router/message-router.d.ts.map +1 -0
  57. package/dist/router/message-router.js +137 -0
  58. package/dist/router/message-router.js.map +1 -0
  59. package/dist/storage/interface.d.ts +31 -0
  60. package/dist/storage/interface.d.ts.map +1 -0
  61. package/dist/storage/interface.js +2 -0
  62. package/dist/storage/interface.js.map +1 -0
  63. package/dist/storage/memory.d.ts +28 -0
  64. package/dist/storage/memory.d.ts.map +1 -0
  65. package/dist/storage/memory.js +118 -0
  66. package/dist/storage/memory.js.map +1 -0
  67. package/dist/storage/sqlite.d.ts +35 -0
  68. package/dist/storage/sqlite.d.ts.map +1 -0
  69. package/dist/storage/sqlite.js +445 -0
  70. package/dist/storage/sqlite.js.map +1 -0
  71. package/dist/traceability/traceability.d.ts +29 -0
  72. package/dist/traceability/traceability.d.ts.map +1 -0
  73. package/dist/traceability/traceability.js +150 -0
  74. package/dist/traceability/traceability.js.map +1 -0
  75. package/dist/types.d.ts +253 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +3 -0
  78. package/dist/types.js.map +1 -0
  79. package/docs/DESIGN.md +1156 -0
  80. package/docs/PLAN.md +545 -0
  81. package/hooks/inbox-hook.mjs +119 -0
  82. package/hooks/register-hook.mjs +69 -0
  83. package/package.json +33 -25
  84. package/rules/agent-inbox.md +78 -0
  85. package/src/federation/address.ts +61 -0
  86. package/src/federation/connection-manager.ts +458 -0
  87. package/src/federation/delivery-queue.ts +222 -0
  88. package/src/federation/index.ts +6 -0
  89. package/src/federation/routing-engine.ts +188 -0
  90. package/src/federation/trust.ts +71 -0
  91. package/src/index.ts +299 -0
  92. package/src/ipc/ipc-server.ts +180 -0
  93. package/src/jsonrpc/mail-server.ts +356 -0
  94. package/src/map/map-client.ts +260 -0
  95. package/src/mcp/mcp-server.ts +272 -0
  96. package/src/push/notifier.ts +192 -0
  97. package/src/registry/warm-registry.ts +210 -0
  98. package/src/router/message-router.ts +175 -0
  99. package/src/storage/interface.ts +48 -0
  100. package/src/storage/memory.ts +145 -0
  101. package/src/storage/sqlite.ts +645 -0
  102. package/src/traceability/traceability.ts +183 -0
  103. package/src/types.ts +287 -0
  104. package/test/federation/address.test.ts +101 -0
  105. package/test/federation/connection-manager.test.ts +546 -0
  106. package/test/federation/delivery-queue.test.ts +159 -0
  107. package/test/federation/integration.test.ts +823 -0
  108. package/test/federation/routing-engine.test.ts +117 -0
  109. package/test/federation/sdk-integration.test.ts +748 -0
  110. package/test/federation/trust.test.ts +89 -0
  111. package/test/ipc-jsonrpc.test.ts +113 -0
  112. package/test/ipc-server.test.ts +138 -0
  113. package/test/mail-server.test.ts +208 -0
  114. package/test/map-client.test.ts +408 -0
  115. package/test/message-router.test.ts +184 -0
  116. package/test/push-notifier.test.ts +139 -0
  117. package/test/registry/warm-registry.test.ts +171 -0
  118. package/test/sqlite-storage.test.ts +243 -0
  119. package/test/storage.test.ts +196 -0
  120. package/test/traceability.test.ts +123 -0
  121. package/tsconfig.json +20 -0
  122. package/tsup.config.ts +10 -0
  123. package/vitest.config.ts +8 -0
  124. package/dist/index.d.mts +0 -2
  125. package/dist/index.mjs +0 -1
  126. package/dist/index.mjs.map +0 -1
@@ -0,0 +1,369 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import * as os from "node:os";
4
+ import * as crypto from "node:crypto";
5
+ import { RoutingEngine } from "./routing-engine.js";
6
+ import { DeliveryQueue } from "./delivery-queue.js";
7
+ import { TrustManager } from "./trust.js";
8
+ import { parseAddress, isRemoteAddress } from "./address.js";
9
+ /**
10
+ * Manages MAP connections and federation peer links.
11
+ *
12
+ * Coordinates routing, delivery queuing, and trust enforcement
13
+ * for cross-system messaging. When an SDK connect function is provided,
14
+ * opens real MAP connections to federation peers for actual message transport.
15
+ */
16
+ export class ConnectionManager {
17
+ events;
18
+ config;
19
+ peers = new Map();
20
+ connections = new Map();
21
+ systemId;
22
+ sdkClass;
23
+ onIncoming;
24
+ routing;
25
+ queue;
26
+ trust;
27
+ constructor(events, config = {}, opts) {
28
+ this.events = events;
29
+ this.config = config;
30
+ this.systemId = this.resolveSystemId();
31
+ this.routing = new RoutingEngine(events, config.routing);
32
+ this.queue = new DeliveryQueue(events, config.deliveryQueue);
33
+ this.trust = new TrustManager(config.trust);
34
+ this.sdkClass = opts?.sdkClass ?? null;
35
+ this.onIncoming = opts?.onIncomingMessage ?? null;
36
+ // Wire up flush-on-reconnect
37
+ this.events.on("federation.connected", (peerId) => {
38
+ if (config.deliveryQueue?.flushOnReconnect !== false) {
39
+ const queued = this.queue.flush(peerId);
40
+ if (queued.length > 0) {
41
+ this.events.emit("federation.flushing", {
42
+ peerId,
43
+ count: queued.length,
44
+ });
45
+ for (const entry of queued) {
46
+ this.route(entry.message).catch(() => {
47
+ // Re-queue if delivery still fails
48
+ this.queue.enqueue(peerId, entry.message);
49
+ });
50
+ }
51
+ }
52
+ }
53
+ });
54
+ }
55
+ /**
56
+ * Get the resolved system ID for this Agent Inbox instance.
57
+ */
58
+ getSystemId() {
59
+ return this.systemId;
60
+ }
61
+ /**
62
+ * Establish federation with a peer. Uses MAP federation/connect protocol.
63
+ * If an SDK class was injected, opens a real MAP connection to the peer.
64
+ * Returns the federation link, or throws if trust check fails.
65
+ */
66
+ async federate(peer) {
67
+ // Trust check
68
+ if (!this.trust.canConnect(peer.systemId)) {
69
+ throw new Error(`Federation denied: system "${peer.systemId}" not in allowed servers list`);
70
+ }
71
+ // Open real MAP connection if SDK is available
72
+ let conn;
73
+ if (this.sdkClass) {
74
+ try {
75
+ conn = await this.sdkClass.connect(peer.url, {
76
+ name: this.systemId.id,
77
+ role: "gateway",
78
+ scopes: ["federation"],
79
+ capabilities: { trajectory: { canReport: false } },
80
+ metadata: {
81
+ systemId: this.systemId.id,
82
+ type: "federation-gateway",
83
+ peerSystemId: peer.systemId,
84
+ },
85
+ reconnection: {
86
+ enabled: true,
87
+ maxRetries: 5,
88
+ baseDelayMs: 1000,
89
+ maxDelayMs: 30000,
90
+ },
91
+ });
92
+ // Register incoming message handler
93
+ conn.onMessage((msg) => {
94
+ this.handlePeerMessage(peer.systemId, msg);
95
+ });
96
+ this.connections.set(peer.systemId, conn);
97
+ }
98
+ catch (err) {
99
+ throw new Error(`Federation connection failed for "${peer.systemId}": ${err instanceof Error ? err.message : err}`);
100
+ }
101
+ }
102
+ const link = {
103
+ peerId: peer.systemId,
104
+ sessionId: crypto.randomUUID(),
105
+ status: "connected",
106
+ exposure: peer.exposure ?? { agents: "all" },
107
+ url: peer.url,
108
+ connectedAt: new Date().toISOString(),
109
+ };
110
+ this.peers.set(peer.systemId, link);
111
+ this.events.emit("federation.connected", peer.systemId);
112
+ return link;
113
+ }
114
+ /**
115
+ * Disconnect from a federation peer.
116
+ * Closes the real MAP connection if one exists.
117
+ */
118
+ async disconnect(peerId) {
119
+ const link = this.peers.get(peerId);
120
+ if (!link)
121
+ return;
122
+ // Close real connection
123
+ const conn = this.connections.get(peerId);
124
+ if (conn) {
125
+ try {
126
+ await conn.disconnect();
127
+ }
128
+ catch {
129
+ // Best-effort disconnect
130
+ }
131
+ this.connections.delete(peerId);
132
+ }
133
+ link.status = "disconnected";
134
+ this.routing.removePeer(peerId);
135
+ this.peers.delete(peerId);
136
+ this.events.emit("federation.disconnected", peerId);
137
+ }
138
+ /**
139
+ * Route a message to the correct federation peer.
140
+ * Resolves the address, checks trust, and delivers or queues.
141
+ * If a real connection exists, sends via conn.send(); otherwise emits event.
142
+ */
143
+ async route(message) {
144
+ // Determine target for each recipient
145
+ for (const recipient of message.recipients) {
146
+ const addr = parseAddress(recipient.agent_id);
147
+ if (!isRemoteAddress(addr))
148
+ continue;
149
+ const peerId = this.routing.resolveRoute(addr);
150
+ if (!peerId) {
151
+ // Route unknown — try strategies
152
+ return this.handleUnknownRoute(addr, message);
153
+ }
154
+ // Check trust
155
+ if (!this.trust.canRoute(peerId, message.scope)) {
156
+ return {
157
+ delivered: false,
158
+ peerId,
159
+ error: `Trust policy denies routing to scope "${message.scope}" from system "${peerId}"`,
160
+ };
161
+ }
162
+ const link = this.peers.get(peerId);
163
+ if (!link || link.status !== "connected") {
164
+ // TODO: When resolved peerId has no peer link (e.g., system-qualified address
165
+ // targeting a system we're not directly connected to), fall through to
166
+ // handleUnknownRoute so broadcast/hierarchical strategies can attempt delivery
167
+ // via connected peers or upstream hubs instead of immediately queuing.
168
+ this.queue.enqueue(peerId, message);
169
+ return { delivered: false, peerId, queued: true };
170
+ }
171
+ // Deliver — use real connection if available, otherwise emit event
172
+ const sendResult = await this.sendToPeer(peerId, addr, message);
173
+ if (sendResult) {
174
+ recipient.delivered_at = new Date().toISOString();
175
+ return { delivered: true, peerId };
176
+ }
177
+ // Send failed — queue for retry
178
+ this.queue.enqueue(peerId, message);
179
+ return { delivered: false, peerId, queued: true };
180
+ }
181
+ return { delivered: false, error: "No remote recipients found" };
182
+ }
183
+ /**
184
+ * Send a message to a peer via real connection or event emission.
185
+ * Returns true if send succeeded (or event was emitted).
186
+ */
187
+ async sendToPeer(peerId, addr, message) {
188
+ const conn = this.connections.get(peerId);
189
+ if (conn) {
190
+ // Real transport — send via MAP SDK connection
191
+ try {
192
+ await conn.send({ agentId: addr.agent, scope: addr.scope }, message.content, {
193
+ messageId: message.id,
194
+ senderId: message.sender_id,
195
+ sourceSystem: this.systemId.id,
196
+ targetAgent: addr.agent,
197
+ importance: message.importance,
198
+ ...(message.subject ? { subject: message.subject } : {}),
199
+ ...(message.thread_tag ? { threadTag: message.thread_tag } : {}),
200
+ ...(message.in_reply_to ? { inReplyTo: message.in_reply_to } : {}),
201
+ });
202
+ return true;
203
+ }
204
+ catch {
205
+ return false;
206
+ }
207
+ }
208
+ // No real connection — emit event (for testing / event-based mode)
209
+ this.events.emit("federation.route", { peerId, message });
210
+ return true;
211
+ }
212
+ /**
213
+ * Handle an incoming message from a federation peer connection.
214
+ * Delegates to the injected message handler (wired to router.routeMessage).
215
+ */
216
+ handlePeerMessage(peerId, msg) {
217
+ this.events.emit("federation.message.received", { peerId, message: msg });
218
+ if (this.onIncoming) {
219
+ this.onIncoming({
220
+ from: msg.from,
221
+ peerId,
222
+ payload: msg.payload,
223
+ meta: msg.meta,
224
+ });
225
+ }
226
+ }
227
+ /**
228
+ * Handle routing to an unknown agent. Behavior depends on strategy.
229
+ */
230
+ async handleUnknownRoute(addr, message) {
231
+ const strategy = this.routing.getStrategy();
232
+ if (strategy === "broadcast") {
233
+ // Forward to all connected peers
234
+ const connectedPeers = this.getConnectedPeers();
235
+ if (connectedPeers.length === 0) {
236
+ return { delivered: false, error: "No connected peers for broadcast" };
237
+ }
238
+ // Try real connections first, fall back to event
239
+ for (const peer of connectedPeers) {
240
+ await this.sendToPeer(peer.peerId, addr, message);
241
+ }
242
+ this.events.emit("federation.broadcast", {
243
+ message,
244
+ peers: connectedPeers.map((p) => p.peerId),
245
+ timeout: this.routing.getBroadcastTimeout(),
246
+ });
247
+ return { delivered: true };
248
+ }
249
+ if (strategy === "hierarchical") {
250
+ // Delegate to upstream hubs
251
+ const upstream = this.routing.getUpstream();
252
+ for (const hubId of upstream) {
253
+ const link = this.peers.get(hubId);
254
+ if (link?.status === "connected") {
255
+ const sent = await this.sendToPeer(hubId, addr, message);
256
+ if (sent) {
257
+ return { delivered: true, peerId: hubId };
258
+ }
259
+ }
260
+ }
261
+ return { delivered: false, error: "No reachable upstream hubs" };
262
+ }
263
+ // Table strategy with refreshOnMiss — emit event for transport layer
264
+ if (this.routing.shouldRefreshOnMiss()) {
265
+ this.events.emit("federation.refresh", { address: addr });
266
+ }
267
+ // Queue for later if we have a system hint
268
+ if (addr.system) {
269
+ this.queue.enqueue(addr.system, message);
270
+ return { delivered: false, peerId: addr.system, queued: true };
271
+ }
272
+ return {
273
+ delivered: false,
274
+ error: `No route to agent "${addr.agent}"`,
275
+ };
276
+ }
277
+ /**
278
+ * Get all federation peer links.
279
+ */
280
+ getPeers() {
281
+ return Array.from(this.peers.values());
282
+ }
283
+ /**
284
+ * Get only connected peers.
285
+ */
286
+ getConnectedPeers() {
287
+ return Array.from(this.peers.values()).filter((p) => p.status === "connected");
288
+ }
289
+ /**
290
+ * Get a specific peer link.
291
+ */
292
+ getPeer(peerId) {
293
+ return this.peers.get(peerId);
294
+ }
295
+ /**
296
+ * Check if a peer is connected.
297
+ */
298
+ isConnected(peerId) {
299
+ return this.peers.get(peerId)?.status === "connected";
300
+ }
301
+ /**
302
+ * Check if a real MAP SDK connection exists for a peer.
303
+ */
304
+ hasTransport(peerId) {
305
+ return this.connections.has(peerId);
306
+ }
307
+ /**
308
+ * Clean up all state. Call on shutdown.
309
+ */
310
+ async destroy() {
311
+ // Close all real connections
312
+ for (const [peerId, conn] of this.connections) {
313
+ try {
314
+ await conn.disconnect();
315
+ }
316
+ catch {
317
+ // Best-effort
318
+ }
319
+ this.connections.delete(peerId);
320
+ }
321
+ this.routing.destroy();
322
+ this.queue.destroy();
323
+ this.peers.clear();
324
+ }
325
+ /**
326
+ * Resolve the system ID using tiered precedence:
327
+ * 1. Explicit config (INBOX_SYSTEM_ID)
328
+ * 2. Auto-generated (persisted to file for stability across restarts)
329
+ *
330
+ * Note: Tier 2 (MAP systemInfo) is handled after MAP connection is established.
331
+ */
332
+ resolveSystemId() {
333
+ // Tier 1: Explicit config
334
+ if (this.config.systemId) {
335
+ return { id: this.config.systemId, source: "config" };
336
+ }
337
+ // Tier 3: Auto-generated (with persistence)
338
+ const idFile = path.join(os.homedir(), ".claude", "agent-inbox", "system-id");
339
+ try {
340
+ const existing = fs.readFileSync(idFile, "utf-8").trim();
341
+ if (existing) {
342
+ return { id: existing, source: "auto" };
343
+ }
344
+ }
345
+ catch {
346
+ // File doesn't exist — generate new ID
347
+ }
348
+ const newId = `inbox-${crypto.randomBytes(4).toString("hex")}`;
349
+ try {
350
+ fs.mkdirSync(path.dirname(idFile), { recursive: true });
351
+ fs.writeFileSync(idFile, newId);
352
+ }
353
+ catch {
354
+ // Best-effort persistence
355
+ }
356
+ return { id: newId, source: "auto" };
357
+ }
358
+ /**
359
+ * Update system ID from MAP server's systemInfo (Tier 2).
360
+ * Only used if no explicit config was set.
361
+ */
362
+ updateSystemIdFromMap(mapSystemName) {
363
+ if (this.systemId.source === "config")
364
+ return; // Explicit config takes precedence
365
+ this.systemId = { id: mapSystemName, source: "map" };
366
+ this.events.emit("system.id.updated", this.systemId);
367
+ }
368
+ }
369
+ //# sourceMappingURL=connection-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-manager.js","sourceRoot":"","sources":["../../src/federation/connection-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ import { EventEmitter } from "node:events";
2
+ import type { Message, DeliveryQueueConfig, QueuedMessage } from "../types.js";
3
+ /**
4
+ * Delivery queue for messages to offline or unreachable federation peers.
5
+ *
6
+ * Supports configurable TTL, overflow policy, and retry strategy.
7
+ * Currently memory-only; SQLite persistence is a future enhancement.
8
+ */
9
+ export declare class DeliveryQueue {
10
+ private events;
11
+ private queues;
12
+ private config;
13
+ private tickTimer?;
14
+ constructor(events: EventEmitter, config?: Partial<DeliveryQueueConfig>);
15
+ /**
16
+ * Enqueue a message for a peer. Returns the queued message ID, or null if rejected.
17
+ */
18
+ enqueue(peerId: string, message: Message): string | null;
19
+ /**
20
+ * Flush all queued messages for a peer (on reconnect).
21
+ * Returns the messages and removes them from the queue.
22
+ */
23
+ flush(peerId: string): QueuedMessage[];
24
+ /**
25
+ * Get messages ready for retry. Does not remove them from the queue.
26
+ */
27
+ getRetryable(peerId: string): QueuedMessage[];
28
+ /**
29
+ * Record a retry attempt for a message. Updates attempt count and next retry time.
30
+ * Returns false if max attempts exceeded (message should be dropped).
31
+ */
32
+ recordAttempt(peerId: string, messageId: string): boolean;
33
+ /**
34
+ * Remove a specific entry (e.g., after successful delivery).
35
+ */
36
+ removeEntry(peerId: string, messageId: string): boolean;
37
+ /**
38
+ * Process tick: expire old messages past TTL.
39
+ */
40
+ tick(): number;
41
+ /**
42
+ * Start periodic tick timer for TTL expiry.
43
+ */
44
+ startTicking(intervalMs?: number): void;
45
+ /**
46
+ * Stop periodic tick timer.
47
+ */
48
+ stopTicking(): void;
49
+ /**
50
+ * Get queue depth for a peer.
51
+ */
52
+ size(peerId: string): number;
53
+ /**
54
+ * Get total queue depth across all peers.
55
+ */
56
+ totalSize(): number;
57
+ /**
58
+ * List peers with queued messages.
59
+ */
60
+ peers(): string[];
61
+ /**
62
+ * Clean up all state. Call on shutdown.
63
+ */
64
+ destroy(): void;
65
+ }
66
+ //# sourceMappingURL=delivery-queue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-queue.d.ts","sourceRoot":"","sources":["../../src/federation/delivery-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,OAAO,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAa/E;;;;;GAKG;AACH,qBAAa,aAAa;IAMtB,OAAO,CAAC,MAAM;IALhB,OAAO,CAAC,MAAM,CAAsC;IACpD,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,SAAS,CAAC,CAAiC;gBAGzC,MAAM,EAAE,YAAY,EAC5B,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC;IAKvC;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI;IAmCxD;;;OAGG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE;IAUtC;;OAEG;IACH,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,EAAE;IAW7C;;;OAGG;IACH,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAyBzD;;OAEG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO;IAYvD;;OAEG;IACH,IAAI,IAAI,MAAM;IAyBd;;OAEG;IACH,YAAY,CAAC,UAAU,GAAE,MAAe,GAAG,IAAI;IAK/C;;OAEG;IACH,WAAW,IAAI,IAAI;IAOnB;;OAEG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAI5B;;OAEG;IACH,SAAS,IAAI,MAAM;IAQnB;;OAEG;IACH,KAAK,IAAI,MAAM,EAAE;IAIjB;;OAEG;IACH,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,199 @@
1
+ import { ulid } from "ulid";
2
+ const DEFAULT_CONFIG = {
3
+ persistence: "memory",
4
+ maxTTL: 86_400_000, // 24h
5
+ maxQueueSize: 10_000,
6
+ retryStrategy: "exponential",
7
+ retryBaseInterval: 1_000,
8
+ retryMaxAttempts: 0, // unlimited until TTL
9
+ flushOnReconnect: true,
10
+ overflow: "drop-oldest",
11
+ };
12
+ /**
13
+ * Delivery queue for messages to offline or unreachable federation peers.
14
+ *
15
+ * Supports configurable TTL, overflow policy, and retry strategy.
16
+ * Currently memory-only; SQLite persistence is a future enhancement.
17
+ */
18
+ export class DeliveryQueue {
19
+ events;
20
+ queues = new Map();
21
+ config;
22
+ tickTimer;
23
+ constructor(events, config) {
24
+ this.events = events;
25
+ this.config = { ...DEFAULT_CONFIG, ...config };
26
+ }
27
+ /**
28
+ * Enqueue a message for a peer. Returns the queued message ID, or null if rejected.
29
+ */
30
+ enqueue(peerId, message) {
31
+ let queue = this.queues.get(peerId);
32
+ if (!queue) {
33
+ queue = [];
34
+ this.queues.set(peerId, queue);
35
+ }
36
+ // Check queue size limit
37
+ if (queue.length >= this.config.maxQueueSize) {
38
+ switch (this.config.overflow) {
39
+ case "drop-oldest":
40
+ queue.shift();
41
+ break;
42
+ case "drop-newest":
43
+ return null; // Don't enqueue
44
+ case "reject-new":
45
+ return null;
46
+ }
47
+ }
48
+ const now = new Date().toISOString();
49
+ const entry = {
50
+ id: ulid(),
51
+ peerId,
52
+ message,
53
+ enqueuedAt: now,
54
+ attempts: 0,
55
+ nextRetry: now, // Ready to send immediately
56
+ };
57
+ queue.push(entry);
58
+ this.events.emit("queue.enqueued", { peerId, messageId: entry.id });
59
+ return entry.id;
60
+ }
61
+ /**
62
+ * Flush all queued messages for a peer (on reconnect).
63
+ * Returns the messages and removes them from the queue.
64
+ */
65
+ flush(peerId) {
66
+ const queue = this.queues.get(peerId);
67
+ if (!queue || queue.length === 0)
68
+ return [];
69
+ const messages = [...queue];
70
+ this.queues.delete(peerId);
71
+ this.events.emit("queue.flushed", { peerId, count: messages.length });
72
+ return messages;
73
+ }
74
+ /**
75
+ * Get messages ready for retry. Does not remove them from the queue.
76
+ */
77
+ getRetryable(peerId) {
78
+ const queue = this.queues.get(peerId);
79
+ if (!queue)
80
+ return [];
81
+ const now = Date.now();
82
+ return queue.filter((entry) => {
83
+ if (!entry.nextRetry)
84
+ return true;
85
+ return new Date(entry.nextRetry).getTime() <= now;
86
+ });
87
+ }
88
+ /**
89
+ * Record a retry attempt for a message. Updates attempt count and next retry time.
90
+ * Returns false if max attempts exceeded (message should be dropped).
91
+ */
92
+ recordAttempt(peerId, messageId) {
93
+ const queue = this.queues.get(peerId);
94
+ if (!queue)
95
+ return false;
96
+ const entry = queue.find((e) => e.id === messageId);
97
+ if (!entry)
98
+ return false;
99
+ entry.attempts++;
100
+ entry.lastAttempt = new Date().toISOString();
101
+ // Check max attempts
102
+ if (this.config.retryMaxAttempts > 0 && entry.attempts >= this.config.retryMaxAttempts) {
103
+ this.removeEntry(peerId, messageId);
104
+ return false;
105
+ }
106
+ // Calculate next retry
107
+ const delay = this.config.retryStrategy === "exponential"
108
+ ? this.config.retryBaseInterval * Math.pow(2, entry.attempts - 1)
109
+ : this.config.retryBaseInterval;
110
+ entry.nextRetry = new Date(Date.now() + delay).toISOString();
111
+ return true;
112
+ }
113
+ /**
114
+ * Remove a specific entry (e.g., after successful delivery).
115
+ */
116
+ removeEntry(peerId, messageId) {
117
+ const queue = this.queues.get(peerId);
118
+ if (!queue)
119
+ return false;
120
+ const idx = queue.findIndex((e) => e.id === messageId);
121
+ if (idx === -1)
122
+ return false;
123
+ queue.splice(idx, 1);
124
+ if (queue.length === 0)
125
+ this.queues.delete(peerId);
126
+ return true;
127
+ }
128
+ /**
129
+ * Process tick: expire old messages past TTL.
130
+ */
131
+ tick() {
132
+ const now = Date.now();
133
+ let expired = 0;
134
+ for (const [peerId, queue] of this.queues.entries()) {
135
+ const before = queue.length;
136
+ const remaining = queue.filter((entry) => {
137
+ const age = now - new Date(entry.enqueuedAt).getTime();
138
+ return age < this.config.maxTTL;
139
+ });
140
+ expired += before - remaining.length;
141
+ if (remaining.length === 0) {
142
+ this.queues.delete(peerId);
143
+ }
144
+ else {
145
+ this.queues.set(peerId, remaining);
146
+ }
147
+ }
148
+ if (expired > 0) {
149
+ this.events.emit("queue.expired", { count: expired });
150
+ }
151
+ return expired;
152
+ }
153
+ /**
154
+ * Start periodic tick timer for TTL expiry.
155
+ */
156
+ startTicking(intervalMs = 60_000) {
157
+ this.stopTicking();
158
+ this.tickTimer = setInterval(() => this.tick(), intervalMs);
159
+ }
160
+ /**
161
+ * Stop periodic tick timer.
162
+ */
163
+ stopTicking() {
164
+ if (this.tickTimer) {
165
+ clearInterval(this.tickTimer);
166
+ this.tickTimer = undefined;
167
+ }
168
+ }
169
+ /**
170
+ * Get queue depth for a peer.
171
+ */
172
+ size(peerId) {
173
+ return this.queues.get(peerId)?.length ?? 0;
174
+ }
175
+ /**
176
+ * Get total queue depth across all peers.
177
+ */
178
+ totalSize() {
179
+ let total = 0;
180
+ for (const queue of this.queues.values()) {
181
+ total += queue.length;
182
+ }
183
+ return total;
184
+ }
185
+ /**
186
+ * List peers with queued messages.
187
+ */
188
+ peers() {
189
+ return Array.from(this.queues.keys());
190
+ }
191
+ /**
192
+ * Clean up all state. Call on shutdown.
193
+ */
194
+ destroy() {
195
+ this.stopTicking();
196
+ this.queues.clear();
197
+ }
198
+ }
199
+ //# sourceMappingURL=delivery-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delivery-queue.js","sourceRoot":"","sources":["../../src/federation/delivery-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export { parseAddress, formatAddress, isRemoteAddress, isBroadcastAddress } from "./address.js";
2
+ export { ConnectionManager } from "./connection-manager.js";
3
+ export type { DeliveryResult } from "./connection-manager.js";
4
+ export { DeliveryQueue } from "./delivery-queue.js";
5
+ export { RoutingEngine } from "./routing-engine.js";
6
+ export { TrustManager } from "./trust.js";
7
+ //# sourceMappingURL=index.d.ts.map