@multi-agent-protocol/sdk 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,4528 @@
1
+ 'use strict';
2
+
3
+ var ulid = require('ulid');
4
+ var zod = require('zod');
5
+
6
+ // src/types/index.ts
7
+ function isOrphanedAgent(agent) {
8
+ return agent.ownerId === null;
9
+ }
10
+ var EVENT_TYPES = {
11
+ // Agent lifecycle events
12
+ AGENT_REGISTERED: "agent_registered",
13
+ AGENT_UNREGISTERED: "agent_unregistered",
14
+ AGENT_STATE_CHANGED: "agent_state_changed",
15
+ AGENT_ORPHANED: "agent_orphaned",
16
+ // Participant lifecycle events
17
+ PARTICIPANT_CONNECTED: "participant_connected",
18
+ PARTICIPANT_DISCONNECTED: "participant_disconnected",
19
+ // Message events
20
+ MESSAGE_SENT: "message_sent",
21
+ MESSAGE_DELIVERED: "message_delivered",
22
+ MESSAGE_FAILED: "message_failed",
23
+ // Scope events
24
+ SCOPE_CREATED: "scope_created",
25
+ SCOPE_DELETED: "scope_deleted",
26
+ SCOPE_MEMBER_JOINED: "scope_member_joined",
27
+ SCOPE_MEMBER_LEFT: "scope_member_left",
28
+ // Permission events
29
+ PERMISSIONS_CLIENT_UPDATED: "permissions_client_updated",
30
+ PERMISSIONS_AGENT_UPDATED: "permissions_agent_updated",
31
+ // System events
32
+ SYSTEM_ERROR: "system_error",
33
+ // Federation events
34
+ FEDERATION_CONNECTED: "federation_connected",
35
+ FEDERATION_DISCONNECTED: "federation_disconnected"
36
+ };
37
+ function createEvent(input) {
38
+ return {
39
+ id: `evt-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
40
+ timestamp: input.timestamp ?? Date.now(),
41
+ type: input.type,
42
+ source: input.source,
43
+ data: input.data,
44
+ causedBy: input.causedBy,
45
+ _meta: input._meta
46
+ };
47
+ }
48
+ var JSONRPC_VERSION = "2.0";
49
+ var CORE_METHODS = {
50
+ CONNECT: "map/connect",
51
+ DISCONNECT: "map/disconnect",
52
+ SEND: "map/send",
53
+ SUBSCRIBE: "map/subscribe",
54
+ UNSUBSCRIBE: "map/unsubscribe",
55
+ REPLAY: "map/replay"
56
+ };
57
+ var OBSERVATION_METHODS = {
58
+ AGENTS_LIST: "map/agents/list",
59
+ AGENTS_GET: "map/agents/get",
60
+ SCOPES_LIST: "map/scopes/list",
61
+ SCOPES_GET: "map/scopes/get",
62
+ SCOPES_MEMBERS: "map/scopes/members",
63
+ STRUCTURE_GRAPH: "map/structure/graph"
64
+ };
65
+ var LIFECYCLE_METHODS = {
66
+ AGENTS_REGISTER: "map/agents/register",
67
+ AGENTS_UNREGISTER: "map/agents/unregister",
68
+ AGENTS_SPAWN: "map/agents/spawn"
69
+ };
70
+ var STATE_METHODS = {
71
+ AGENTS_UPDATE: "map/agents/update",
72
+ AGENTS_SUSPEND: "map/agents/suspend",
73
+ AGENTS_RESUME: "map/agents/resume",
74
+ AGENTS_STOP: "map/agents/stop"
75
+ };
76
+ var STEERING_METHODS = {
77
+ INJECT: "map/inject"
78
+ };
79
+ var SCOPE_METHODS = {
80
+ SCOPES_CREATE: "map/scopes/create",
81
+ SCOPES_DELETE: "map/scopes/delete",
82
+ SCOPES_JOIN: "map/scopes/join",
83
+ SCOPES_LEAVE: "map/scopes/leave"
84
+ };
85
+ var SESSION_METHODS = {
86
+ SESSION_LIST: "map/session/list",
87
+ SESSION_LOAD: "map/session/load",
88
+ SESSION_CLOSE: "map/session/close"
89
+ };
90
+ var AUTH_METHODS = {
91
+ AUTH_REFRESH: "map/auth/refresh"
92
+ };
93
+ var PERMISSION_METHODS = {
94
+ PERMISSIONS_UPDATE: "map/permissions/update"
95
+ };
96
+ var FEDERATION_METHODS = {
97
+ FEDERATION_CONNECT: "map/federation/connect",
98
+ FEDERATION_ROUTE: "map/federation/route"
99
+ };
100
+ var NOTIFICATION_METHODS = {
101
+ EVENT: "map/event",
102
+ MESSAGE: "map/message",
103
+ /** Client acknowledges received events (for backpressure) */
104
+ SUBSCRIBE_ACK: "map/subscribe.ack"
105
+ };
106
+ var MAP_METHODS = {
107
+ ...CORE_METHODS,
108
+ ...OBSERVATION_METHODS,
109
+ ...LIFECYCLE_METHODS,
110
+ ...STATE_METHODS,
111
+ ...STEERING_METHODS,
112
+ ...SCOPE_METHODS,
113
+ ...SESSION_METHODS,
114
+ ...AUTH_METHODS,
115
+ ...PERMISSION_METHODS,
116
+ ...FEDERATION_METHODS
117
+ };
118
+ var STRUCTURE_METHODS = {
119
+ ...LIFECYCLE_METHODS,
120
+ ...STATE_METHODS,
121
+ ...SCOPE_METHODS,
122
+ STRUCTURE_GRAPH: OBSERVATION_METHODS.STRUCTURE_GRAPH
123
+ };
124
+ var EXTENSION_METHODS = {
125
+ ...STEERING_METHODS,
126
+ ...FEDERATION_METHODS
127
+ };
128
+ var PROTOCOL_ERROR_CODES = {
129
+ PARSE_ERROR: -32700,
130
+ INVALID_REQUEST: -32600,
131
+ METHOD_NOT_FOUND: -32601,
132
+ INVALID_PARAMS: -32602,
133
+ INTERNAL_ERROR: -32603
134
+ };
135
+ var AUTH_ERROR_CODES = {
136
+ AUTH_REQUIRED: 1e3,
137
+ AUTH_FAILED: 1001,
138
+ TOKEN_EXPIRED: 1002,
139
+ PERMISSION_DENIED: 1003
140
+ };
141
+ var ROUTING_ERROR_CODES = {
142
+ ADDRESS_NOT_FOUND: 2e3,
143
+ AGENT_NOT_FOUND: 2001,
144
+ SCOPE_NOT_FOUND: 2002,
145
+ DELIVERY_FAILED: 2003,
146
+ ADDRESS_AMBIGUOUS: 2004
147
+ };
148
+ var AGENT_ERROR_CODES = {
149
+ AGENT_EXISTS: 3e3,
150
+ STATE_INVALID: 3001,
151
+ NOT_RESPONDING: 3002,
152
+ TERMINATED: 3003,
153
+ SPAWN_FAILED: 3004
154
+ };
155
+ var RESOURCE_ERROR_CODES = {
156
+ EXHAUSTED: 4e3,
157
+ RATE_LIMITED: 4001,
158
+ QUOTA_EXCEEDED: 4002
159
+ };
160
+ var FEDERATION_ERROR_CODES = {
161
+ FEDERATION_UNAVAILABLE: 5e3,
162
+ FEDERATION_SYSTEM_NOT_FOUND: 5001,
163
+ FEDERATION_AUTH_FAILED: 5002,
164
+ FEDERATION_ROUTE_REJECTED: 5003,
165
+ /** Message has already visited this system (loop detected) */
166
+ FEDERATION_LOOP_DETECTED: 5010,
167
+ /** Message exceeded maximum hop count */
168
+ FEDERATION_MAX_HOPS_EXCEEDED: 5011
169
+ };
170
+ var ERROR_CODES = {
171
+ ...PROTOCOL_ERROR_CODES,
172
+ ...AUTH_ERROR_CODES,
173
+ ...ROUTING_ERROR_CODES,
174
+ ...AGENT_ERROR_CODES,
175
+ ...RESOURCE_ERROR_CODES,
176
+ ...FEDERATION_ERROR_CODES
177
+ };
178
+ var PROTOCOL_VERSION = 1;
179
+ var CAPABILITY_REQUIREMENTS = {
180
+ // Core
181
+ [CORE_METHODS.CONNECT]: [],
182
+ [CORE_METHODS.DISCONNECT]: [],
183
+ [CORE_METHODS.SEND]: ["messaging.canSend"],
184
+ [CORE_METHODS.SUBSCRIBE]: ["observation.canObserve"],
185
+ [CORE_METHODS.UNSUBSCRIBE]: ["observation.canObserve"],
186
+ // Observation
187
+ [OBSERVATION_METHODS.AGENTS_LIST]: ["observation.canQuery"],
188
+ [OBSERVATION_METHODS.AGENTS_GET]: ["observation.canQuery"],
189
+ [OBSERVATION_METHODS.SCOPES_LIST]: ["observation.canQuery"],
190
+ [OBSERVATION_METHODS.SCOPES_GET]: ["observation.canQuery"],
191
+ [OBSERVATION_METHODS.SCOPES_MEMBERS]: ["observation.canQuery"],
192
+ [OBSERVATION_METHODS.STRUCTURE_GRAPH]: ["observation.canQuery"],
193
+ // Lifecycle
194
+ [LIFECYCLE_METHODS.AGENTS_REGISTER]: ["lifecycle.canRegister"],
195
+ [LIFECYCLE_METHODS.AGENTS_UNREGISTER]: ["lifecycle.canUnregister"],
196
+ [LIFECYCLE_METHODS.AGENTS_SPAWN]: ["lifecycle.canSpawn"],
197
+ // State
198
+ [STATE_METHODS.AGENTS_UPDATE]: ["lifecycle.canRegister"],
199
+ [STATE_METHODS.AGENTS_SUSPEND]: ["lifecycle.canStop"],
200
+ [STATE_METHODS.AGENTS_RESUME]: ["lifecycle.canStop"],
201
+ [STATE_METHODS.AGENTS_STOP]: ["lifecycle.canStop"],
202
+ // Steering
203
+ [STEERING_METHODS.INJECT]: ["lifecycle.canSteer"],
204
+ // Scopes
205
+ [SCOPE_METHODS.SCOPES_CREATE]: ["scopes.canCreateScopes"],
206
+ [SCOPE_METHODS.SCOPES_DELETE]: ["scopes.canManageScopes"],
207
+ [SCOPE_METHODS.SCOPES_JOIN]: [],
208
+ [SCOPE_METHODS.SCOPES_LEAVE]: [],
209
+ // Session
210
+ [SESSION_METHODS.SESSION_LIST]: [],
211
+ [SESSION_METHODS.SESSION_LOAD]: [],
212
+ [SESSION_METHODS.SESSION_CLOSE]: [],
213
+ // Auth
214
+ [AUTH_METHODS.AUTH_REFRESH]: [],
215
+ // Permissions (system-only, no capability check - enforced by participant type)
216
+ [PERMISSION_METHODS.PERMISSIONS_UPDATE]: [],
217
+ // Federation
218
+ [FEDERATION_METHODS.FEDERATION_CONNECT]: ["federation.canFederate"],
219
+ [FEDERATION_METHODS.FEDERATION_ROUTE]: ["federation.canFederate"]
220
+ };
221
+ function isSuccessResponse(response) {
222
+ return "result" in response;
223
+ }
224
+ function isDirectAddress(address) {
225
+ return typeof address === "object" && "agent" in address && !("system" in address);
226
+ }
227
+ function isFederatedAddress(address) {
228
+ return typeof address === "object" && "system" in address && "agent" in address;
229
+ }
230
+ function isScopeAddress(address) {
231
+ return typeof address === "object" && "scope" in address;
232
+ }
233
+ function isBroadcastAddress(address) {
234
+ return typeof address === "object" && "broadcast" in address;
235
+ }
236
+ function isHierarchicalAddress(address) {
237
+ return typeof address === "object" && ("parent" in address || "children" in address || "ancestors" in address || "descendants" in address || "siblings" in address);
238
+ }
239
+
240
+ // src/jsonrpc/index.ts
241
+ function isRequest(message) {
242
+ return typeof message === "object" && message !== null && "jsonrpc" in message && message.jsonrpc === "2.0" && "id" in message && "method" in message;
243
+ }
244
+ function isNotification(message) {
245
+ return typeof message === "object" && message !== null && "jsonrpc" in message && message.jsonrpc === "2.0" && "method" in message && !("id" in message);
246
+ }
247
+ function isResponse(message) {
248
+ return typeof message === "object" && message !== null && "jsonrpc" in message && message.jsonrpc === "2.0" && "id" in message && !("method" in message);
249
+ }
250
+ function isErrorResponse(response) {
251
+ return "error" in response;
252
+ }
253
+ function createRequest(id, method, params) {
254
+ const request = {
255
+ jsonrpc: "2.0",
256
+ id,
257
+ method
258
+ };
259
+ if (params !== void 0) {
260
+ request.params = params;
261
+ }
262
+ return request;
263
+ }
264
+ function createNotification(method, params) {
265
+ const notification = {
266
+ jsonrpc: "2.0",
267
+ method
268
+ };
269
+ if (params !== void 0) {
270
+ notification.params = params;
271
+ }
272
+ return notification;
273
+ }
274
+ function createSuccessResponse(id, result) {
275
+ return {
276
+ jsonrpc: "2.0",
277
+ id,
278
+ result
279
+ };
280
+ }
281
+ function createErrorResponse(id, error) {
282
+ return {
283
+ jsonrpc: "2.0",
284
+ id,
285
+ error
286
+ };
287
+ }
288
+
289
+ // src/errors/index.ts
290
+ var MAPRequestError = class _MAPRequestError extends Error {
291
+ code;
292
+ data;
293
+ constructor(code, message, data) {
294
+ super(message);
295
+ this.name = "MAPRequestError";
296
+ this.code = code;
297
+ this.data = data;
298
+ }
299
+ /**
300
+ * Convert to MAP error object
301
+ */
302
+ toError() {
303
+ const error = {
304
+ code: this.code,
305
+ message: this.message
306
+ };
307
+ if (this.data) {
308
+ error.data = this.data;
309
+ }
310
+ return error;
311
+ }
312
+ /**
313
+ * Convert to JSON-RPC error response
314
+ */
315
+ toResponse(id) {
316
+ return createErrorResponse(id, this.toError());
317
+ }
318
+ // ==========================================================================
319
+ // Protocol Errors (-32xxx)
320
+ // ==========================================================================
321
+ static parseError(details) {
322
+ return new _MAPRequestError(
323
+ PROTOCOL_ERROR_CODES.PARSE_ERROR,
324
+ details ?? "Parse error",
325
+ { category: "protocol" }
326
+ );
327
+ }
328
+ static invalidRequest(details) {
329
+ return new _MAPRequestError(
330
+ PROTOCOL_ERROR_CODES.INVALID_REQUEST,
331
+ details ?? "Invalid request",
332
+ { category: "protocol" }
333
+ );
334
+ }
335
+ static methodNotFound(method) {
336
+ return new _MAPRequestError(
337
+ PROTOCOL_ERROR_CODES.METHOD_NOT_FOUND,
338
+ `Method not found: ${method}`,
339
+ { category: "protocol" }
340
+ );
341
+ }
342
+ static invalidParams(details) {
343
+ return new _MAPRequestError(
344
+ PROTOCOL_ERROR_CODES.INVALID_PARAMS,
345
+ "Invalid params",
346
+ { category: "protocol", details }
347
+ );
348
+ }
349
+ static internalError(details) {
350
+ return new _MAPRequestError(
351
+ PROTOCOL_ERROR_CODES.INTERNAL_ERROR,
352
+ details ?? "Internal error",
353
+ { category: "internal" }
354
+ );
355
+ }
356
+ // ==========================================================================
357
+ // Auth Errors (1xxx)
358
+ // ==========================================================================
359
+ static authRequired() {
360
+ return new _MAPRequestError(
361
+ AUTH_ERROR_CODES.AUTH_REQUIRED,
362
+ "Authentication required",
363
+ { category: "auth" }
364
+ );
365
+ }
366
+ static authFailed(details) {
367
+ return new _MAPRequestError(
368
+ AUTH_ERROR_CODES.AUTH_FAILED,
369
+ details ?? "Authentication failed",
370
+ { category: "auth" }
371
+ );
372
+ }
373
+ static tokenExpired() {
374
+ return new _MAPRequestError(
375
+ AUTH_ERROR_CODES.TOKEN_EXPIRED,
376
+ "Token expired",
377
+ { category: "auth", retryable: true }
378
+ );
379
+ }
380
+ static permissionDenied(required) {
381
+ return new _MAPRequestError(
382
+ AUTH_ERROR_CODES.PERMISSION_DENIED,
383
+ required ? `Permission denied: ${required}` : "Permission denied",
384
+ { category: "auth" }
385
+ );
386
+ }
387
+ // ==========================================================================
388
+ // Routing Errors (2xxx)
389
+ // ==========================================================================
390
+ static addressNotFound(address) {
391
+ return new _MAPRequestError(
392
+ ROUTING_ERROR_CODES.ADDRESS_NOT_FOUND,
393
+ `Address not found: ${address}`,
394
+ { category: "routing" }
395
+ );
396
+ }
397
+ static agentNotFound(agentId) {
398
+ return new _MAPRequestError(
399
+ ROUTING_ERROR_CODES.AGENT_NOT_FOUND,
400
+ `Agent not found: ${agentId}`,
401
+ { category: "routing" }
402
+ );
403
+ }
404
+ static scopeNotFound(scopeId) {
405
+ return new _MAPRequestError(
406
+ ROUTING_ERROR_CODES.SCOPE_NOT_FOUND,
407
+ `Scope not found: ${scopeId}`,
408
+ { category: "routing" }
409
+ );
410
+ }
411
+ static deliveryFailed(details) {
412
+ return new _MAPRequestError(
413
+ ROUTING_ERROR_CODES.DELIVERY_FAILED,
414
+ details ?? "Message delivery failed",
415
+ { category: "routing", retryable: true }
416
+ );
417
+ }
418
+ static addressAmbiguous(address) {
419
+ return new _MAPRequestError(
420
+ ROUTING_ERROR_CODES.ADDRESS_AMBIGUOUS,
421
+ `Address is ambiguous: ${address}`,
422
+ { category: "routing" }
423
+ );
424
+ }
425
+ // ==========================================================================
426
+ // Agent Errors (3xxx)
427
+ // ==========================================================================
428
+ static agentExists(agentId) {
429
+ return new _MAPRequestError(
430
+ AGENT_ERROR_CODES.AGENT_EXISTS,
431
+ `Agent already exists: ${agentId}`,
432
+ { category: "agent" }
433
+ );
434
+ }
435
+ static stateInvalid(currentState, requestedAction) {
436
+ return new _MAPRequestError(
437
+ AGENT_ERROR_CODES.STATE_INVALID,
438
+ `Cannot ${requestedAction} agent in state: ${currentState}`,
439
+ { category: "agent" }
440
+ );
441
+ }
442
+ static agentNotResponding(agentId) {
443
+ return new _MAPRequestError(
444
+ AGENT_ERROR_CODES.NOT_RESPONDING,
445
+ `Agent not responding: ${agentId}`,
446
+ { category: "agent", retryable: true }
447
+ );
448
+ }
449
+ static agentTerminated(agentId) {
450
+ return new _MAPRequestError(
451
+ AGENT_ERROR_CODES.TERMINATED,
452
+ `Agent terminated: ${agentId}`,
453
+ { category: "agent" }
454
+ );
455
+ }
456
+ static spawnFailed(details) {
457
+ return new _MAPRequestError(
458
+ AGENT_ERROR_CODES.SPAWN_FAILED,
459
+ details ?? "Failed to spawn agent",
460
+ { category: "agent" }
461
+ );
462
+ }
463
+ // ==========================================================================
464
+ // Resource Errors (4xxx)
465
+ // ==========================================================================
466
+ static resourceExhausted(resource) {
467
+ return new _MAPRequestError(
468
+ RESOURCE_ERROR_CODES.EXHAUSTED,
469
+ resource ? `Resource exhausted: ${resource}` : "Resource exhausted",
470
+ { category: "resource", retryable: true }
471
+ );
472
+ }
473
+ static rateLimited(retryAfterMs) {
474
+ return new _MAPRequestError(
475
+ RESOURCE_ERROR_CODES.RATE_LIMITED,
476
+ "Rate limited",
477
+ { category: "resource", retryable: true, retryAfterMs }
478
+ );
479
+ }
480
+ static quotaExceeded(quota) {
481
+ return new _MAPRequestError(
482
+ RESOURCE_ERROR_CODES.QUOTA_EXCEEDED,
483
+ quota ? `Quota exceeded: ${quota}` : "Quota exceeded",
484
+ { category: "resource" }
485
+ );
486
+ }
487
+ // ==========================================================================
488
+ // Federation Errors (5xxx)
489
+ // ==========================================================================
490
+ static federationUnavailable(systemId) {
491
+ return new _MAPRequestError(
492
+ FEDERATION_ERROR_CODES.FEDERATION_UNAVAILABLE,
493
+ systemId ? `Federation unavailable: ${systemId}` : "Federation unavailable",
494
+ { category: "federation", retryable: true }
495
+ );
496
+ }
497
+ static federationSystemNotFound(systemId) {
498
+ return new _MAPRequestError(
499
+ FEDERATION_ERROR_CODES.FEDERATION_SYSTEM_NOT_FOUND,
500
+ `System not found: ${systemId}`,
501
+ { category: "federation" }
502
+ );
503
+ }
504
+ static federationAuthFailed(systemId) {
505
+ return new _MAPRequestError(
506
+ FEDERATION_ERROR_CODES.FEDERATION_AUTH_FAILED,
507
+ `Federation authentication failed: ${systemId}`,
508
+ { category: "federation" }
509
+ );
510
+ }
511
+ static federationRouteRejected(systemId, reason) {
512
+ return new _MAPRequestError(
513
+ FEDERATION_ERROR_CODES.FEDERATION_ROUTE_REJECTED,
514
+ reason ? `Route rejected by ${systemId}: ${reason}` : `Route rejected by ${systemId}`,
515
+ { category: "federation" }
516
+ );
517
+ }
518
+ // ==========================================================================
519
+ // Utility
520
+ // ==========================================================================
521
+ /**
522
+ * Create from a MAP error object
523
+ */
524
+ static fromError(error) {
525
+ return new _MAPRequestError(error.code, error.message, error.data);
526
+ }
527
+ /**
528
+ * Check if this error is retryable
529
+ */
530
+ get retryable() {
531
+ return this.data?.retryable ?? false;
532
+ }
533
+ /**
534
+ * Get retry delay in milliseconds, if specified
535
+ */
536
+ get retryAfterMs() {
537
+ return this.data?.retryAfterMs;
538
+ }
539
+ /**
540
+ * Get error category
541
+ */
542
+ get category() {
543
+ return this.data?.category;
544
+ }
545
+ };
546
+ var MAPConnectionError = class _MAPConnectionError extends Error {
547
+ constructor(message) {
548
+ super(message);
549
+ this.name = "MAPConnectionError";
550
+ }
551
+ static closed() {
552
+ return new _MAPConnectionError("Connection closed");
553
+ }
554
+ static timeout() {
555
+ return new _MAPConnectionError("Connection timeout");
556
+ }
557
+ };
558
+ var MAPTimeoutError = class extends Error {
559
+ timeoutMs;
560
+ constructor(operation, timeoutMs) {
561
+ super(`Operation timed out after ${timeoutMs}ms: ${operation}`);
562
+ this.name = "MAPTimeoutError";
563
+ this.timeoutMs = timeoutMs;
564
+ }
565
+ };
566
+
567
+ // src/stream/index.ts
568
+ function ndJsonStream(readable, writable) {
569
+ const encoder = new TextEncoder();
570
+ const decoder = new TextDecoder();
571
+ let buffer = "";
572
+ const messageReadable = new ReadableStream({
573
+ async start(controller) {
574
+ const reader = readable.getReader();
575
+ try {
576
+ while (true) {
577
+ const { done, value } = await reader.read();
578
+ if (done) {
579
+ if (buffer.trim()) {
580
+ try {
581
+ const message = JSON.parse(buffer.trim());
582
+ controller.enqueue(message);
583
+ } catch {
584
+ console.error("MAP: Failed to parse final message:", buffer);
585
+ }
586
+ }
587
+ controller.close();
588
+ break;
589
+ }
590
+ buffer += decoder.decode(value, { stream: true });
591
+ const lines = buffer.split("\n");
592
+ buffer = lines.pop() ?? "";
593
+ for (const line of lines) {
594
+ const trimmed = line.trim();
595
+ if (trimmed) {
596
+ try {
597
+ const message = JSON.parse(trimmed);
598
+ controller.enqueue(message);
599
+ } catch {
600
+ console.error("MAP: Failed to parse message:", trimmed);
601
+ }
602
+ }
603
+ }
604
+ }
605
+ } catch (error) {
606
+ controller.error(error);
607
+ } finally {
608
+ reader.releaseLock();
609
+ }
610
+ }
611
+ });
612
+ const messageWritable = new WritableStream({
613
+ async write(message) {
614
+ const writer = writable.getWriter();
615
+ try {
616
+ const json = JSON.stringify(message) + "\n";
617
+ await writer.write(encoder.encode(json));
618
+ } finally {
619
+ writer.releaseLock();
620
+ }
621
+ },
622
+ async close() {
623
+ await writable.close();
624
+ },
625
+ abort(reason) {
626
+ writable.abort(reason);
627
+ }
628
+ });
629
+ return {
630
+ readable: messageReadable,
631
+ writable: messageWritable
632
+ };
633
+ }
634
+ function websocketStream(ws) {
635
+ const messageQueue = [];
636
+ let messageResolver = null;
637
+ let closed = false;
638
+ let closeError = null;
639
+ ws.addEventListener("message", (event) => {
640
+ try {
641
+ const message = JSON.parse(event.data);
642
+ if (messageResolver) {
643
+ messageResolver({ value: message, done: false });
644
+ messageResolver = null;
645
+ } else {
646
+ messageQueue.push(message);
647
+ }
648
+ } catch {
649
+ console.error("MAP: Failed to parse WebSocket message:", event.data);
650
+ }
651
+ });
652
+ ws.addEventListener("close", () => {
653
+ closed = true;
654
+ if (messageResolver) {
655
+ messageResolver({ value: void 0, done: true });
656
+ messageResolver = null;
657
+ }
658
+ });
659
+ ws.addEventListener("error", () => {
660
+ closeError = new Error("WebSocket error");
661
+ closed = true;
662
+ if (messageResolver) {
663
+ messageResolver({ value: void 0, done: true });
664
+ messageResolver = null;
665
+ }
666
+ });
667
+ const readable = new ReadableStream({
668
+ async pull(controller) {
669
+ if (messageQueue.length > 0) {
670
+ controller.enqueue(messageQueue.shift());
671
+ return;
672
+ }
673
+ if (closed) {
674
+ if (closeError) {
675
+ controller.error(closeError);
676
+ } else {
677
+ controller.close();
678
+ }
679
+ return;
680
+ }
681
+ await new Promise((resolve) => {
682
+ messageResolver = resolve;
683
+ }).then((result) => {
684
+ if (result.done) {
685
+ controller.close();
686
+ } else {
687
+ controller.enqueue(result.value);
688
+ }
689
+ });
690
+ }
691
+ });
692
+ const writable = new WritableStream({
693
+ async write(message) {
694
+ if (ws.readyState === WebSocket.CONNECTING) {
695
+ await new Promise((resolve, reject) => {
696
+ const onOpen = () => {
697
+ ws.removeEventListener("error", onError);
698
+ resolve();
699
+ };
700
+ const onError = () => {
701
+ ws.removeEventListener("open", onOpen);
702
+ reject(new Error("WebSocket failed to connect"));
703
+ };
704
+ ws.addEventListener("open", onOpen, { once: true });
705
+ ws.addEventListener("error", onError, { once: true });
706
+ });
707
+ }
708
+ if (ws.readyState !== WebSocket.OPEN) {
709
+ throw new Error("WebSocket is not open");
710
+ }
711
+ ws.send(JSON.stringify(message));
712
+ },
713
+ close() {
714
+ ws.close();
715
+ },
716
+ abort() {
717
+ ws.close();
718
+ }
719
+ });
720
+ return { readable, writable };
721
+ }
722
+ function createStreamPair() {
723
+ const clientToServer = [];
724
+ const serverToClient = [];
725
+ let clientToServerResolver = null;
726
+ let serverToClientResolver = null;
727
+ let clientToServerClosed = false;
728
+ let serverToClientClosed = false;
729
+ function createReadable(queue, _getResolver, setResolver, isClosed) {
730
+ return new ReadableStream({
731
+ async pull(controller) {
732
+ if (queue.length > 0) {
733
+ controller.enqueue(queue.shift());
734
+ return;
735
+ }
736
+ if (isClosed()) {
737
+ controller.close();
738
+ return;
739
+ }
740
+ const message = await new Promise((resolve) => {
741
+ setResolver((msg) => {
742
+ setResolver(null);
743
+ resolve(msg);
744
+ });
745
+ });
746
+ if (message === null) {
747
+ controller.close();
748
+ } else {
749
+ controller.enqueue(message);
750
+ }
751
+ }
752
+ });
753
+ }
754
+ function createWritable(queue, getResolver, setClosed) {
755
+ return new WritableStream({
756
+ write(message) {
757
+ const resolver = getResolver();
758
+ if (resolver) {
759
+ resolver(message);
760
+ } else {
761
+ queue.push(message);
762
+ }
763
+ },
764
+ close() {
765
+ setClosed();
766
+ const resolver = getResolver();
767
+ if (resolver) {
768
+ resolver(null);
769
+ }
770
+ }
771
+ });
772
+ }
773
+ const clientStream = {
774
+ // Client writes to server
775
+ writable: createWritable(
776
+ clientToServer,
777
+ () => clientToServerResolver,
778
+ () => {
779
+ clientToServerClosed = true;
780
+ }
781
+ ),
782
+ // Client reads from server
783
+ readable: createReadable(
784
+ serverToClient,
785
+ () => serverToClientResolver,
786
+ (r) => {
787
+ serverToClientResolver = r;
788
+ },
789
+ () => serverToClientClosed
790
+ )
791
+ };
792
+ const serverStream = {
793
+ // Server writes to client
794
+ writable: createWritable(
795
+ serverToClient,
796
+ () => serverToClientResolver,
797
+ () => {
798
+ serverToClientClosed = true;
799
+ }
800
+ ),
801
+ // Server reads from client
802
+ readable: createReadable(
803
+ clientToServer,
804
+ () => clientToServerResolver,
805
+ (r) => {
806
+ clientToServerResolver = r;
807
+ },
808
+ () => clientToServerClosed
809
+ )
810
+ };
811
+ return [clientStream, serverStream];
812
+ }
813
+
814
+ // src/subscription/index.ts
815
+ var Subscription = class {
816
+ id;
817
+ filter;
818
+ #eventHandlers = /* @__PURE__ */ new Set();
819
+ #overflowHandlers = /* @__PURE__ */ new Set();
820
+ #eventQueue = [];
821
+ #bufferSize;
822
+ #unsubscribe;
823
+ #sendAck;
824
+ // Deduplication tracking
825
+ #seenEventIds = /* @__PURE__ */ new Set();
826
+ #seenEventIdOrder = [];
827
+ // For LRU eviction
828
+ #maxSeenEventIds;
829
+ #eventResolver = null;
830
+ #pauseResolver = null;
831
+ #state = "active";
832
+ #lastSequenceNumber = -1;
833
+ #lastEventId;
834
+ #lastTimestamp;
835
+ // Overflow tracking
836
+ #totalDropped = 0;
837
+ #oldestDroppedId;
838
+ #newestDroppedId;
839
+ // Ack support
840
+ #serverSupportsAck = false;
841
+ constructor(id, unsubscribe, options = {}, sendAck) {
842
+ this.id = id;
843
+ this.filter = options.filter;
844
+ this.#bufferSize = options.bufferSize ?? 1e3;
845
+ this.#maxSeenEventIds = options.maxSeenEventIds ?? 1e4;
846
+ this.#unsubscribe = unsubscribe;
847
+ this.#sendAck = sendAck;
848
+ }
849
+ /**
850
+ * Current subscription state
851
+ */
852
+ get state() {
853
+ return this.#state;
854
+ }
855
+ /**
856
+ * Whether the subscription is closed
857
+ */
858
+ get isClosed() {
859
+ return this.#state === "closed";
860
+ }
861
+ /**
862
+ * Whether the subscription is paused
863
+ */
864
+ get isPaused() {
865
+ return this.#state === "paused";
866
+ }
867
+ /**
868
+ * Last received sequence number (for ordering verification)
869
+ */
870
+ get lastSequenceNumber() {
871
+ return this.#lastSequenceNumber;
872
+ }
873
+ /**
874
+ * Last received eventId (for replay positioning)
875
+ */
876
+ get lastEventId() {
877
+ return this.#lastEventId;
878
+ }
879
+ /**
880
+ * Last received server timestamp
881
+ */
882
+ get lastTimestamp() {
883
+ return this.#lastTimestamp;
884
+ }
885
+ /**
886
+ * Number of events currently buffered
887
+ */
888
+ get bufferedCount() {
889
+ return this.#eventQueue.length;
890
+ }
891
+ /**
892
+ * Number of eventIds being tracked for deduplication
893
+ */
894
+ get trackedEventIdCount() {
895
+ return this.#seenEventIds.size;
896
+ }
897
+ /**
898
+ * Total number of events dropped due to buffer overflow
899
+ */
900
+ get totalDropped() {
901
+ return this.#totalDropped;
902
+ }
903
+ /**
904
+ * Whether the server supports acknowledgments
905
+ */
906
+ get supportsAck() {
907
+ return this.#serverSupportsAck && !!this.#sendAck;
908
+ }
909
+ /**
910
+ * Pause event delivery from the async iterator.
911
+ * Events are still buffered but not yielded until resume() is called.
912
+ * Event handlers (on('event', ...)) still receive events while paused.
913
+ */
914
+ pause() {
915
+ if (this.#state === "closed") return;
916
+ this.#state = "paused";
917
+ }
918
+ /**
919
+ * Resume event delivery from the async iterator.
920
+ * Any events buffered during pause will be yielded.
921
+ */
922
+ resume() {
923
+ if (this.#state === "closed") return;
924
+ this.#state = "active";
925
+ if (this.#pauseResolver) {
926
+ this.#pauseResolver();
927
+ this.#pauseResolver = null;
928
+ }
929
+ if (this.#eventResolver && this.#eventQueue.length > 0) {
930
+ const event = this.#eventQueue.shift();
931
+ this.#eventResolver(event);
932
+ this.#eventResolver = null;
933
+ }
934
+ }
935
+ /**
936
+ * Acknowledge events up to a sequence number.
937
+ * No-op if server doesn't support acks.
938
+ *
939
+ * @param upToSequence - Acknowledge all events up to and including this sequence.
940
+ * If omitted, acknowledges up to lastSequenceNumber.
941
+ */
942
+ ack(upToSequence) {
943
+ if (!this.supportsAck) return;
944
+ const seq = upToSequence ?? this.#lastSequenceNumber;
945
+ if (seq < 0) return;
946
+ this.#sendAck({
947
+ subscriptionId: this.id,
948
+ upToSequence: seq
949
+ });
950
+ }
951
+ on(type, handler) {
952
+ if (type === "event") {
953
+ this.#eventHandlers.add(handler);
954
+ } else if (type === "overflow") {
955
+ this.#overflowHandlers.add(handler);
956
+ }
957
+ return this;
958
+ }
959
+ off(type, handler) {
960
+ if (type === "event") {
961
+ this.#eventHandlers.delete(handler);
962
+ } else if (type === "overflow") {
963
+ this.#overflowHandlers.delete(handler);
964
+ }
965
+ return this;
966
+ }
967
+ /**
968
+ * Register a one-time event handler
969
+ */
970
+ once(type, handler) {
971
+ if (type === "event") {
972
+ const wrapper = (event) => {
973
+ this.off("event", wrapper);
974
+ handler(event);
975
+ };
976
+ this.on("event", wrapper);
977
+ }
978
+ return this;
979
+ }
980
+ /**
981
+ * Unsubscribe and close the subscription
982
+ */
983
+ async unsubscribe() {
984
+ if (this.#state === "closed") return;
985
+ this.#state = "closed";
986
+ if (this.#eventResolver) {
987
+ this.#eventResolver(null);
988
+ this.#eventResolver = null;
989
+ }
990
+ if (this.#pauseResolver) {
991
+ this.#pauseResolver();
992
+ this.#pauseResolver = null;
993
+ }
994
+ this.#eventHandlers.clear();
995
+ this.#overflowHandlers.clear();
996
+ this.#seenEventIds.clear();
997
+ this.#seenEventIdOrder.length = 0;
998
+ await this.#unsubscribe();
999
+ }
1000
+ /**
1001
+ * Set whether server supports acknowledgments.
1002
+ * Called by connection after capability negotiation.
1003
+ * @internal
1004
+ */
1005
+ _setServerSupportsAck(supports) {
1006
+ this.#serverSupportsAck = supports;
1007
+ }
1008
+ /**
1009
+ * Push an event to the subscription (called by connection)
1010
+ * @internal
1011
+ */
1012
+ _pushEvent(params) {
1013
+ if (this.#state === "closed") return;
1014
+ const { sequenceNumber, eventId, timestamp, event } = params;
1015
+ if (eventId) {
1016
+ if (this.#seenEventIds.has(eventId)) {
1017
+ return;
1018
+ }
1019
+ this.#seenEventIds.add(eventId);
1020
+ this.#seenEventIdOrder.push(eventId);
1021
+ while (this.#seenEventIds.size > this.#maxSeenEventIds) {
1022
+ const oldestId = this.#seenEventIdOrder.shift();
1023
+ if (oldestId) {
1024
+ this.#seenEventIds.delete(oldestId);
1025
+ }
1026
+ }
1027
+ this.#lastEventId = eventId;
1028
+ }
1029
+ if (timestamp !== void 0) {
1030
+ this.#lastTimestamp = timestamp;
1031
+ }
1032
+ if (this.#lastSequenceNumber >= 0 && sequenceNumber !== this.#lastSequenceNumber + 1) {
1033
+ console.warn(
1034
+ `MAP: Subscription ${this.id} sequence gap: expected ${this.#lastSequenceNumber + 1}, got ${sequenceNumber}`
1035
+ );
1036
+ }
1037
+ this.#lastSequenceNumber = sequenceNumber;
1038
+ for (const handler of this.#eventHandlers) {
1039
+ try {
1040
+ handler(event);
1041
+ } catch (error) {
1042
+ console.error("MAP: Event handler error:", error);
1043
+ }
1044
+ }
1045
+ if (this.#eventResolver && this.#state === "active") {
1046
+ this.#eventResolver(event);
1047
+ this.#eventResolver = null;
1048
+ return;
1049
+ }
1050
+ if (this.#eventQueue.length < this.#bufferSize) {
1051
+ this.#eventQueue.push(event);
1052
+ } else {
1053
+ this.#totalDropped++;
1054
+ if (eventId) {
1055
+ if (this.#oldestDroppedId === void 0) {
1056
+ this.#oldestDroppedId = eventId;
1057
+ }
1058
+ this.#newestDroppedId = eventId;
1059
+ }
1060
+ const info = {
1061
+ eventsDropped: 1,
1062
+ oldestDroppedId: this.#oldestDroppedId,
1063
+ newestDroppedId: this.#newestDroppedId,
1064
+ timestamp: Date.now(),
1065
+ totalDropped: this.#totalDropped
1066
+ };
1067
+ for (const handler of this.#overflowHandlers) {
1068
+ try {
1069
+ handler(info);
1070
+ } catch (error) {
1071
+ console.error("MAP: Overflow handler error:", error);
1072
+ }
1073
+ }
1074
+ console.warn(`MAP: Subscription ${this.id} buffer full, dropping event`);
1075
+ }
1076
+ }
1077
+ /**
1078
+ * Mark the subscription as closed (called by connection)
1079
+ * @internal
1080
+ */
1081
+ _close() {
1082
+ this.#state = "closed";
1083
+ if (this.#eventResolver) {
1084
+ this.#eventResolver(null);
1085
+ this.#eventResolver = null;
1086
+ }
1087
+ if (this.#pauseResolver) {
1088
+ this.#pauseResolver();
1089
+ this.#pauseResolver = null;
1090
+ }
1091
+ }
1092
+ /**
1093
+ * Async iterator implementation
1094
+ */
1095
+ async *[Symbol.asyncIterator]() {
1096
+ while (!this.isClosed) {
1097
+ while (this.isPaused) {
1098
+ await new Promise((resolve) => {
1099
+ this.#pauseResolver = resolve;
1100
+ });
1101
+ if (this.isClosed) {
1102
+ while (this.#eventQueue.length > 0) {
1103
+ yield this.#eventQueue.shift();
1104
+ }
1105
+ return;
1106
+ }
1107
+ }
1108
+ if (this.#eventQueue.length > 0) {
1109
+ yield this.#eventQueue.shift();
1110
+ continue;
1111
+ }
1112
+ const event = await new Promise((resolve) => {
1113
+ this.#eventResolver = resolve;
1114
+ });
1115
+ if (event === null) {
1116
+ break;
1117
+ }
1118
+ yield event;
1119
+ }
1120
+ while (this.#eventQueue.length > 0) {
1121
+ yield this.#eventQueue.shift();
1122
+ }
1123
+ }
1124
+ };
1125
+ function createSubscription(id, unsubscribe, options, sendAck) {
1126
+ return new Subscription(id, unsubscribe, options, sendAck);
1127
+ }
1128
+
1129
+ // src/connection/base.ts
1130
+ var BaseConnection = class {
1131
+ #stream;
1132
+ #pendingResponses = /* @__PURE__ */ new Map();
1133
+ #abortController = new AbortController();
1134
+ #closedPromise;
1135
+ #defaultTimeout;
1136
+ #stateChangeHandlers = /* @__PURE__ */ new Set();
1137
+ #nextRequestId = 1;
1138
+ #writeQueue = Promise.resolve();
1139
+ #requestHandler = null;
1140
+ #notificationHandler = null;
1141
+ #closed = false;
1142
+ #closeResolver;
1143
+ #state = "initial";
1144
+ constructor(stream, options = {}) {
1145
+ this.#stream = stream;
1146
+ this.#defaultTimeout = options.defaultTimeout ?? 3e4;
1147
+ this.#closedPromise = new Promise((resolve) => {
1148
+ this.#closeResolver = resolve;
1149
+ });
1150
+ void this.#startReceiving();
1151
+ }
1152
+ /**
1153
+ * AbortSignal that triggers when the connection closes.
1154
+ * Useful for cancelling operations tied to this connection.
1155
+ */
1156
+ get signal() {
1157
+ return this.#abortController.signal;
1158
+ }
1159
+ /**
1160
+ * Promise that resolves when the connection is closed.
1161
+ */
1162
+ get closed() {
1163
+ return this.#closedPromise;
1164
+ }
1165
+ /**
1166
+ * Whether the connection is closed
1167
+ */
1168
+ get isClosed() {
1169
+ return this.#closed;
1170
+ }
1171
+ /**
1172
+ * Set the handler for incoming requests
1173
+ */
1174
+ setRequestHandler(handler) {
1175
+ this.#requestHandler = handler;
1176
+ }
1177
+ /**
1178
+ * Set the handler for incoming notifications
1179
+ */
1180
+ setNotificationHandler(handler) {
1181
+ this.#notificationHandler = handler;
1182
+ }
1183
+ /**
1184
+ * Current connection state
1185
+ */
1186
+ get state() {
1187
+ return this.#state;
1188
+ }
1189
+ /**
1190
+ * Register a handler for state changes.
1191
+ *
1192
+ * @param handler - Function called when state changes
1193
+ * @returns Unsubscribe function to remove the handler
1194
+ */
1195
+ onStateChange(handler) {
1196
+ this.#stateChangeHandlers.add(handler);
1197
+ return () => this.#stateChangeHandlers.delete(handler);
1198
+ }
1199
+ /**
1200
+ * Transition to a new state and notify handlers.
1201
+ * @internal
1202
+ */
1203
+ _transitionTo(newState) {
1204
+ if (this.#state === newState) return;
1205
+ const oldState = this.#state;
1206
+ this.#state = newState;
1207
+ for (const handler of this.#stateChangeHandlers) {
1208
+ try {
1209
+ handler(newState, oldState);
1210
+ } catch (error) {
1211
+ console.error("MAP: State change handler error:", error);
1212
+ }
1213
+ }
1214
+ }
1215
+ /**
1216
+ * Reconnect with a new stream.
1217
+ *
1218
+ * This method is used by role-specific connections to replace the
1219
+ * underlying transport after a disconnect.
1220
+ *
1221
+ * @param newStream - The new stream to use
1222
+ * @throws If the connection is permanently closed
1223
+ */
1224
+ async reconnect(newStream) {
1225
+ if (this.#state === "closed") {
1226
+ throw new Error("Cannot reconnect a permanently closed connection");
1227
+ }
1228
+ this.#stream = newStream;
1229
+ this.#closed = false;
1230
+ this.#writeQueue = Promise.resolve();
1231
+ void this.#startReceiving();
1232
+ this._transitionTo("connected");
1233
+ }
1234
+ /**
1235
+ * Send a request and wait for response
1236
+ */
1237
+ async sendRequest(method, params, options) {
1238
+ if (this.#closed) {
1239
+ throw MAPConnectionError.closed();
1240
+ }
1241
+ const id = this.#nextRequestId++;
1242
+ const request = createRequest(id, method, params);
1243
+ const responsePromise = new Promise((resolve, reject) => {
1244
+ const pending = { resolve, reject };
1245
+ const timeout = options?.timeout ?? this.#defaultTimeout;
1246
+ if (timeout > 0) {
1247
+ pending.timeoutId = setTimeout(() => {
1248
+ this.#pendingResponses.delete(id);
1249
+ reject(new MAPTimeoutError(method, timeout));
1250
+ }, timeout);
1251
+ }
1252
+ this.#pendingResponses.set(id, pending);
1253
+ });
1254
+ await this.#sendMessage(request);
1255
+ return responsePromise;
1256
+ }
1257
+ /**
1258
+ * Send a notification (no response expected)
1259
+ */
1260
+ async sendNotification(method, params) {
1261
+ if (this.#closed) {
1262
+ throw MAPConnectionError.closed();
1263
+ }
1264
+ const notification = createNotification(method, params);
1265
+ await this.#sendMessage(notification);
1266
+ }
1267
+ /**
1268
+ * Send a response to a request
1269
+ */
1270
+ async sendResponse(id, result) {
1271
+ if (this.#closed) {
1272
+ throw MAPConnectionError.closed();
1273
+ }
1274
+ const response = createSuccessResponse(id, result);
1275
+ await this.#sendMessage(response);
1276
+ }
1277
+ /**
1278
+ * Send an error response to a request
1279
+ */
1280
+ async sendErrorResponse(id, error) {
1281
+ if (this.#closed) {
1282
+ throw MAPConnectionError.closed();
1283
+ }
1284
+ const response = createErrorResponse(id, error);
1285
+ await this.#sendMessage(response);
1286
+ }
1287
+ /**
1288
+ * Close the connection
1289
+ */
1290
+ async close() {
1291
+ if (this.#closed) return;
1292
+ this.#closed = true;
1293
+ this._transitionTo("closed");
1294
+ this.#abortController.abort();
1295
+ for (const [, pending] of this.#pendingResponses) {
1296
+ if (pending.timeoutId) {
1297
+ clearTimeout(pending.timeoutId);
1298
+ }
1299
+ pending.reject(MAPConnectionError.closed());
1300
+ }
1301
+ this.#pendingResponses.clear();
1302
+ try {
1303
+ const writer = this.#stream.writable.getWriter();
1304
+ await writer.close();
1305
+ writer.releaseLock();
1306
+ } catch {
1307
+ }
1308
+ this.#closeResolver();
1309
+ }
1310
+ /**
1311
+ * Start receiving messages from the stream
1312
+ */
1313
+ async #startReceiving() {
1314
+ const reader = this.#stream.readable.getReader();
1315
+ try {
1316
+ while (!this.#closed) {
1317
+ const { done, value } = await reader.read();
1318
+ if (done) {
1319
+ break;
1320
+ }
1321
+ await this.#handleMessage(value);
1322
+ }
1323
+ } catch (error) {
1324
+ if (!this.#closed) {
1325
+ console.error("MAP: Error receiving message:", error);
1326
+ }
1327
+ } finally {
1328
+ reader.releaseLock();
1329
+ await this.close();
1330
+ }
1331
+ }
1332
+ /**
1333
+ * Handle an incoming message
1334
+ */
1335
+ async #handleMessage(message) {
1336
+ try {
1337
+ if (isRequest(message)) {
1338
+ await this.#handleRequest(message);
1339
+ } else if (isNotification(message)) {
1340
+ await this.#handleNotification(message);
1341
+ } else if (isResponse(message)) {
1342
+ this.#handleResponse(message);
1343
+ } else {
1344
+ console.error("MAP: Unknown message type:", message);
1345
+ }
1346
+ } catch (error) {
1347
+ console.error("MAP: Error handling message:", error);
1348
+ }
1349
+ }
1350
+ /**
1351
+ * Handle an incoming request
1352
+ */
1353
+ async #handleRequest(request) {
1354
+ const { id, method, params } = request;
1355
+ if (!this.#requestHandler) {
1356
+ await this.sendErrorResponse(
1357
+ id,
1358
+ MAPRequestError.methodNotFound(method).toError()
1359
+ );
1360
+ return;
1361
+ }
1362
+ try {
1363
+ const result = await this.#requestHandler(method, params);
1364
+ await this.sendResponse(id, result ?? null);
1365
+ } catch (error) {
1366
+ if (error instanceof MAPRequestError) {
1367
+ await this.sendErrorResponse(id, error.toError());
1368
+ } else {
1369
+ const message = error instanceof Error ? error.message : "Unknown error";
1370
+ await this.sendErrorResponse(
1371
+ id,
1372
+ MAPRequestError.internalError(message).toError()
1373
+ );
1374
+ }
1375
+ }
1376
+ }
1377
+ /**
1378
+ * Handle an incoming notification
1379
+ */
1380
+ async #handleNotification(notification) {
1381
+ const { method, params } = notification;
1382
+ if (!this.#notificationHandler) {
1383
+ console.warn("MAP: No notification handler for:", method);
1384
+ return;
1385
+ }
1386
+ try {
1387
+ await this.#notificationHandler(method, params);
1388
+ } catch (error) {
1389
+ console.error("MAP: Error handling notification:", method, error);
1390
+ }
1391
+ }
1392
+ /**
1393
+ * Handle an incoming response
1394
+ */
1395
+ #handleResponse(response) {
1396
+ const { id } = response;
1397
+ const pending = this.#pendingResponses.get(id);
1398
+ if (!pending) {
1399
+ console.warn("MAP: Received response for unknown request:", id);
1400
+ return;
1401
+ }
1402
+ this.#pendingResponses.delete(id);
1403
+ if (pending.timeoutId) {
1404
+ clearTimeout(pending.timeoutId);
1405
+ }
1406
+ if (isErrorResponse(response)) {
1407
+ pending.reject(MAPRequestError.fromError(response.error));
1408
+ } else {
1409
+ pending.resolve(response.result);
1410
+ }
1411
+ }
1412
+ /**
1413
+ * Send a message through the stream with write queue serialization
1414
+ */
1415
+ async #sendMessage(message) {
1416
+ this.#writeQueue = this.#writeQueue.then(async () => {
1417
+ if (this.#closed) return;
1418
+ const writer = this.#stream.writable.getWriter();
1419
+ try {
1420
+ await writer.write(message);
1421
+ } finally {
1422
+ writer.releaseLock();
1423
+ }
1424
+ }).catch((error) => {
1425
+ console.error("MAP: Write error:", error);
1426
+ });
1427
+ return this.#writeQueue;
1428
+ }
1429
+ };
1430
+ var ENCODING = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
1431
+ var ENCODING_LEN = ENCODING.length;
1432
+ function ulidTimestamp(id) {
1433
+ if (id.length !== 26) {
1434
+ throw new Error(`Invalid ULID: expected 26 characters, got ${id.length}`);
1435
+ }
1436
+ let time = 0;
1437
+ for (let i = 0; i < 10; i++) {
1438
+ const char = id[i].toUpperCase();
1439
+ const idx = ENCODING.indexOf(char);
1440
+ if (idx === -1) {
1441
+ throw new Error(`Invalid ULID character: ${char}`);
1442
+ }
1443
+ time = time * ENCODING_LEN + idx;
1444
+ }
1445
+ return time;
1446
+ }
1447
+ function compareUlid(a, b) {
1448
+ return a.localeCompare(b);
1449
+ }
1450
+ function isValidUlid(id) {
1451
+ if (typeof id !== "string" || id.length !== 26) {
1452
+ return false;
1453
+ }
1454
+ for (let i = 0; i < 26; i++) {
1455
+ if (ENCODING.indexOf(id[i].toUpperCase()) === -1) {
1456
+ return false;
1457
+ }
1458
+ }
1459
+ return true;
1460
+ }
1461
+
1462
+ // src/utils/retry.ts
1463
+ var DEFAULT_RETRY_POLICY = {
1464
+ maxRetries: 10,
1465
+ baseDelayMs: 1e3,
1466
+ maxDelayMs: 3e4,
1467
+ jitter: true
1468
+ };
1469
+ function calculateDelay(attempt, policy) {
1470
+ let delay = Math.min(
1471
+ policy.baseDelayMs * Math.pow(2, attempt - 1),
1472
+ policy.maxDelayMs
1473
+ );
1474
+ if (policy.jitter) {
1475
+ delay = delay * (0.5 + Math.random());
1476
+ }
1477
+ return Math.floor(delay);
1478
+ }
1479
+ async function withRetry(operation, policy = DEFAULT_RETRY_POLICY, callbacks) {
1480
+ let lastError;
1481
+ for (let attempt = 1; attempt <= policy.maxRetries + 1; attempt++) {
1482
+ try {
1483
+ const result = await operation();
1484
+ callbacks?.onSuccess?.(result, attempt);
1485
+ return result;
1486
+ } catch (error) {
1487
+ lastError = error;
1488
+ const isRetryable = policy.isRetryable?.(lastError) ?? true;
1489
+ const hasMoreAttempts = attempt <= policy.maxRetries;
1490
+ if (!isRetryable || !hasMoreAttempts) {
1491
+ break;
1492
+ }
1493
+ const delay = calculateDelay(attempt, policy);
1494
+ callbacks?.onRetry?.({
1495
+ attempt,
1496
+ nextDelayMs: delay,
1497
+ lastError
1498
+ });
1499
+ await sleep(delay);
1500
+ }
1501
+ }
1502
+ callbacks?.onFailure?.(lastError, policy.maxRetries + 1);
1503
+ throw lastError;
1504
+ }
1505
+ function retryable(fn, policy = DEFAULT_RETRY_POLICY) {
1506
+ return (...args) => withRetry(() => fn(...args), policy);
1507
+ }
1508
+ function createRetryPolicy(options = {}) {
1509
+ return { ...DEFAULT_RETRY_POLICY, ...options };
1510
+ }
1511
+ function sleep(ms) {
1512
+ return new Promise((resolve) => setTimeout(resolve, ms));
1513
+ }
1514
+
1515
+ // src/utils/causal-buffer.ts
1516
+ var CausalEventBuffer = class {
1517
+ #options;
1518
+ /** Events seen (by eventId) - used to check if predecessors exist */
1519
+ #seen = /* @__PURE__ */ new Set();
1520
+ /** Events waiting for predecessors */
1521
+ #pending = /* @__PURE__ */ new Map();
1522
+ /** Map from eventId to events waiting for it */
1523
+ #waitingFor = /* @__PURE__ */ new Map();
1524
+ constructor(options = {}) {
1525
+ this.#options = {
1526
+ maxWaitTime: options.maxWaitTime ?? 5e3,
1527
+ maxBufferSize: options.maxBufferSize ?? 1e3,
1528
+ onForcedRelease: options.onForcedRelease
1529
+ };
1530
+ }
1531
+ /**
1532
+ * Push an event into the buffer.
1533
+ *
1534
+ * @param event - The event to buffer
1535
+ * @returns Events that are ready to be processed (in causal order)
1536
+ */
1537
+ push(event) {
1538
+ const ready = [];
1539
+ if (this.#seen.has(event.eventId)) {
1540
+ return { ready, pending: this.#pending.size };
1541
+ }
1542
+ this.#seen.add(event.eventId);
1543
+ if (!event.receivedAt) {
1544
+ event = { ...event, receivedAt: Date.now() };
1545
+ }
1546
+ const missingPredecessors = this.#getMissingPredecessors(event);
1547
+ if (missingPredecessors.length === 0) {
1548
+ ready.push(event);
1549
+ this.#releaseWaiting(event.eventId, ready);
1550
+ } else {
1551
+ this.#pending.set(event.eventId, event);
1552
+ for (const predecessorId of missingPredecessors) {
1553
+ if (!this.#waitingFor.has(predecessorId)) {
1554
+ this.#waitingFor.set(predecessorId, /* @__PURE__ */ new Set());
1555
+ }
1556
+ this.#waitingFor.get(predecessorId).add(event.eventId);
1557
+ }
1558
+ }
1559
+ this.#handleBufferOverflow(ready);
1560
+ this.#handleTimeouts(ready);
1561
+ return { ready, pending: this.#pending.size };
1562
+ }
1563
+ /**
1564
+ * Get the number of events waiting for predecessors
1565
+ */
1566
+ get pendingCount() {
1567
+ return this.#pending.size;
1568
+ }
1569
+ /**
1570
+ * Get the number of unique events seen
1571
+ */
1572
+ get seenCount() {
1573
+ return this.#seen.size;
1574
+ }
1575
+ /**
1576
+ * Check if a specific event has been seen
1577
+ */
1578
+ hasSeen(eventId) {
1579
+ return this.#seen.has(eventId);
1580
+ }
1581
+ /**
1582
+ * Force release all pending events, regardless of missing predecessors.
1583
+ * Useful for cleanup or when you know no more events are coming.
1584
+ *
1585
+ * @returns All pending events in the order they would be released
1586
+ */
1587
+ flush() {
1588
+ const ready = [];
1589
+ const pendingList = Array.from(this.#pending.values()).sort(
1590
+ (a, b) => (a.receivedAt ?? 0) - (b.receivedAt ?? 0)
1591
+ );
1592
+ for (const event of pendingList) {
1593
+ const missingPredecessors = this.#getMissingPredecessors(event);
1594
+ if (missingPredecessors.length > 0) {
1595
+ this.#options.onForcedRelease?.(event, missingPredecessors);
1596
+ }
1597
+ ready.push(event);
1598
+ }
1599
+ this.#pending.clear();
1600
+ this.#waitingFor.clear();
1601
+ return ready;
1602
+ }
1603
+ /**
1604
+ * Clear all state (seen events, pending events)
1605
+ */
1606
+ clear() {
1607
+ this.#seen.clear();
1608
+ this.#pending.clear();
1609
+ this.#waitingFor.clear();
1610
+ }
1611
+ /**
1612
+ * Get missing predecessors for an event.
1613
+ * A predecessor is considered "missing" if it hasn't been released yet
1614
+ * (either not seen at all, or seen but still pending).
1615
+ */
1616
+ #getMissingPredecessors(event) {
1617
+ if (!event.causedBy || event.causedBy.length === 0) {
1618
+ return [];
1619
+ }
1620
+ return event.causedBy.filter((predecessorId) => {
1621
+ return !this.#seen.has(predecessorId) || this.#pending.has(predecessorId);
1622
+ });
1623
+ }
1624
+ /**
1625
+ * Release events that were waiting for a specific predecessor
1626
+ */
1627
+ #releaseWaiting(predecessorId, ready) {
1628
+ const waitingEventIds = this.#waitingFor.get(predecessorId);
1629
+ if (!waitingEventIds) return;
1630
+ this.#waitingFor.delete(predecessorId);
1631
+ for (const waitingEventId of waitingEventIds) {
1632
+ const waitingEvent = this.#pending.get(waitingEventId);
1633
+ if (!waitingEvent) continue;
1634
+ const stillMissing = this.#getMissingPredecessors(waitingEvent);
1635
+ if (stillMissing.length === 0) {
1636
+ this.#pending.delete(waitingEventId);
1637
+ ready.push(waitingEvent);
1638
+ this.#releaseWaiting(waitingEventId, ready);
1639
+ }
1640
+ }
1641
+ }
1642
+ /**
1643
+ * Handle buffer overflow by force-releasing oldest events
1644
+ */
1645
+ #handleBufferOverflow(ready) {
1646
+ while (this.#pending.size > this.#options.maxBufferSize) {
1647
+ let oldest = null;
1648
+ for (const event of this.#pending.values()) {
1649
+ if (!oldest || (event.receivedAt ?? 0) < (oldest.receivedAt ?? 0)) {
1650
+ oldest = event;
1651
+ }
1652
+ }
1653
+ if (oldest) {
1654
+ this.#forceRelease(oldest, ready);
1655
+ }
1656
+ }
1657
+ }
1658
+ /**
1659
+ * Handle events that have been waiting too long
1660
+ */
1661
+ #handleTimeouts(ready) {
1662
+ if (this.#options.maxWaitTime <= 0 || this.#options.maxWaitTime === Infinity) {
1663
+ return;
1664
+ }
1665
+ const now = Date.now();
1666
+ const toRelease = [];
1667
+ for (const event of this.#pending.values()) {
1668
+ const waitTime = now - (event.receivedAt ?? now);
1669
+ if (waitTime >= this.#options.maxWaitTime) {
1670
+ toRelease.push(event);
1671
+ }
1672
+ }
1673
+ for (const event of toRelease) {
1674
+ this.#forceRelease(event, ready);
1675
+ }
1676
+ }
1677
+ /**
1678
+ * Force release an event despite missing predecessors
1679
+ */
1680
+ #forceRelease(event, ready) {
1681
+ const missingPredecessors = this.#getMissingPredecessors(event);
1682
+ this.#pending.delete(event.eventId);
1683
+ for (const predecessorId of event.causedBy ?? []) {
1684
+ const waiting = this.#waitingFor.get(predecessorId);
1685
+ if (waiting) {
1686
+ waiting.delete(event.eventId);
1687
+ if (waiting.size === 0) {
1688
+ this.#waitingFor.delete(predecessorId);
1689
+ }
1690
+ }
1691
+ }
1692
+ if (missingPredecessors.length > 0) {
1693
+ this.#options.onForcedRelease?.(event, missingPredecessors);
1694
+ }
1695
+ ready.push(event);
1696
+ this.#releaseWaiting(event.eventId, ready);
1697
+ }
1698
+ };
1699
+ function validateCausalOrder(events) {
1700
+ const seen = /* @__PURE__ */ new Set();
1701
+ for (const event of events) {
1702
+ if (event.causedBy) {
1703
+ for (const predecessorId of event.causedBy) {
1704
+ if (!seen.has(predecessorId)) {
1705
+ return false;
1706
+ }
1707
+ }
1708
+ }
1709
+ seen.add(event.eventId);
1710
+ }
1711
+ return true;
1712
+ }
1713
+ function sortCausalOrder(events) {
1714
+ const eventMap = /* @__PURE__ */ new Map();
1715
+ for (const event of events) {
1716
+ eventMap.set(event.eventId, event);
1717
+ }
1718
+ const result = [];
1719
+ const visited = /* @__PURE__ */ new Set();
1720
+ const visiting = /* @__PURE__ */ new Set();
1721
+ function visit(eventId) {
1722
+ if (visited.has(eventId)) return;
1723
+ if (visiting.has(eventId)) {
1724
+ throw new Error(`Cycle detected involving event: ${eventId}`);
1725
+ }
1726
+ const event = eventMap.get(eventId);
1727
+ if (!event) {
1728
+ throw new Error(`Missing event: ${eventId}`);
1729
+ }
1730
+ visiting.add(eventId);
1731
+ if (event.causedBy) {
1732
+ for (const predecessorId of event.causedBy) {
1733
+ if (!eventMap.has(predecessorId)) {
1734
+ throw new Error(`Missing predecessor: ${predecessorId} for event: ${eventId}`);
1735
+ }
1736
+ visit(predecessorId);
1737
+ }
1738
+ }
1739
+ visiting.delete(eventId);
1740
+ visited.add(eventId);
1741
+ result.push(event);
1742
+ }
1743
+ for (const event of events) {
1744
+ visit(event.eventId);
1745
+ }
1746
+ return result;
1747
+ }
1748
+
1749
+ // src/connection/client.ts
1750
+ var ClientConnection = class {
1751
+ #connection;
1752
+ #subscriptions = /* @__PURE__ */ new Map();
1753
+ #subscriptionStates = /* @__PURE__ */ new Map();
1754
+ #reconnectionHandlers = /* @__PURE__ */ new Set();
1755
+ #options;
1756
+ #sessionId = null;
1757
+ #serverCapabilities = null;
1758
+ #connected = false;
1759
+ #lastConnectOptions;
1760
+ #isReconnecting = false;
1761
+ constructor(stream, options = {}) {
1762
+ this.#connection = new BaseConnection(stream, options);
1763
+ this.#options = options;
1764
+ this.#connection.setNotificationHandler(this.#handleNotification.bind(this));
1765
+ if (options.reconnection?.enabled && options.createStream) {
1766
+ this.#connection.onStateChange((newState) => {
1767
+ if (newState === "closed" && this.#connected && !this.#isReconnecting) {
1768
+ void this.#handleDisconnect();
1769
+ }
1770
+ });
1771
+ }
1772
+ }
1773
+ // ===========================================================================
1774
+ // Connection Lifecycle
1775
+ // ===========================================================================
1776
+ /**
1777
+ * Connect to the MAP system
1778
+ */
1779
+ async connect(options) {
1780
+ const params = {
1781
+ protocolVersion: PROTOCOL_VERSION,
1782
+ participantType: "client",
1783
+ name: this.#options.name,
1784
+ capabilities: this.#options.capabilities,
1785
+ sessionId: options?.sessionId,
1786
+ auth: options?.auth
1787
+ };
1788
+ const result = await this.#connection.sendRequest(CORE_METHODS.CONNECT, params);
1789
+ this.#sessionId = result.sessionId;
1790
+ this.#serverCapabilities = result.capabilities;
1791
+ this.#connected = true;
1792
+ this.#connection._transitionTo("connected");
1793
+ this.#lastConnectOptions = options;
1794
+ return result;
1795
+ }
1796
+ /**
1797
+ * Disconnect from the MAP system
1798
+ */
1799
+ async disconnect(reason) {
1800
+ if (!this.#connected) return;
1801
+ try {
1802
+ await this.#connection.sendRequest(
1803
+ CORE_METHODS.DISCONNECT,
1804
+ reason ? { reason } : void 0
1805
+ );
1806
+ } finally {
1807
+ for (const subscription of this.#subscriptions.values()) {
1808
+ subscription._close();
1809
+ }
1810
+ this.#subscriptions.clear();
1811
+ await this.#connection.close();
1812
+ this.#connected = false;
1813
+ }
1814
+ }
1815
+ /**
1816
+ * Whether the client is connected
1817
+ */
1818
+ get isConnected() {
1819
+ return this.#connected && !this.#connection.isClosed;
1820
+ }
1821
+ /**
1822
+ * Current session ID
1823
+ */
1824
+ get sessionId() {
1825
+ return this.#sessionId;
1826
+ }
1827
+ /**
1828
+ * Server capabilities
1829
+ */
1830
+ get serverCapabilities() {
1831
+ return this.#serverCapabilities;
1832
+ }
1833
+ /**
1834
+ * AbortSignal that triggers when the connection closes
1835
+ */
1836
+ get signal() {
1837
+ return this.#connection.signal;
1838
+ }
1839
+ /**
1840
+ * Promise that resolves when the connection closes
1841
+ */
1842
+ get closed() {
1843
+ return this.#connection.closed;
1844
+ }
1845
+ // ===========================================================================
1846
+ // Session Management
1847
+ // ===========================================================================
1848
+ /**
1849
+ * List available sessions
1850
+ */
1851
+ async listSessions() {
1852
+ return this.#connection.sendRequest(SESSION_METHODS.SESSION_LIST);
1853
+ }
1854
+ /**
1855
+ * Load an existing session
1856
+ */
1857
+ async loadSession(sessionId) {
1858
+ return this.#connection.sendRequest(SESSION_METHODS.SESSION_LOAD, { sessionId });
1859
+ }
1860
+ /**
1861
+ * Close the current session
1862
+ */
1863
+ async closeSession(sessionId) {
1864
+ return this.#connection.sendRequest(SESSION_METHODS.SESSION_CLOSE, { sessionId });
1865
+ }
1866
+ // ===========================================================================
1867
+ // Agent Queries
1868
+ // ===========================================================================
1869
+ /**
1870
+ * List agents with optional filters
1871
+ */
1872
+ async listAgents(options) {
1873
+ return this.#connection.sendRequest(OBSERVATION_METHODS.AGENTS_LIST, options);
1874
+ }
1875
+ /**
1876
+ * Get a single agent by ID
1877
+ */
1878
+ async getAgent(agentId, options) {
1879
+ const params = { agentId, ...options };
1880
+ return this.#connection.sendRequest(
1881
+ OBSERVATION_METHODS.AGENTS_GET,
1882
+ params
1883
+ );
1884
+ }
1885
+ /**
1886
+ * Get the agent structure/hierarchy graph
1887
+ */
1888
+ async getStructureGraph(options) {
1889
+ return this.#connection.sendRequest(OBSERVATION_METHODS.STRUCTURE_GRAPH, options);
1890
+ }
1891
+ // ===========================================================================
1892
+ // Scope Queries
1893
+ // ===========================================================================
1894
+ /**
1895
+ * List scopes
1896
+ */
1897
+ async listScopes(options) {
1898
+ return this.#connection.sendRequest(OBSERVATION_METHODS.SCOPES_LIST, options);
1899
+ }
1900
+ /**
1901
+ * Get a single scope by ID
1902
+ */
1903
+ async getScope(scopeId) {
1904
+ const result = await this.#connection.sendRequest(OBSERVATION_METHODS.SCOPES_GET, { scopeId });
1905
+ return result.scope;
1906
+ }
1907
+ /**
1908
+ * List members of a scope
1909
+ */
1910
+ async getScopeMembers(scopeId, options) {
1911
+ return this.#connection.sendRequest(OBSERVATION_METHODS.SCOPES_MEMBERS, {
1912
+ scopeId,
1913
+ ...options
1914
+ });
1915
+ }
1916
+ // ===========================================================================
1917
+ // Messaging
1918
+ // ===========================================================================
1919
+ /**
1920
+ * Send a message to an address
1921
+ */
1922
+ async send(to, payload, meta) {
1923
+ const params = { to };
1924
+ if (payload !== void 0) params.payload = payload;
1925
+ if (meta) params.meta = meta;
1926
+ return this.#connection.sendRequest(CORE_METHODS.SEND, params);
1927
+ }
1928
+ /**
1929
+ * Send a message to a specific agent
1930
+ */
1931
+ async sendToAgent(agentId, payload, meta) {
1932
+ return this.send({ agent: agentId }, payload, meta);
1933
+ }
1934
+ /**
1935
+ * Send a message to all agents in a scope
1936
+ */
1937
+ async sendToScope(scopeId, payload, meta) {
1938
+ return this.send({ scope: scopeId }, payload, meta);
1939
+ }
1940
+ /**
1941
+ * Send a message to agents with a specific role
1942
+ */
1943
+ async sendToRole(role, payload, meta, withinScope) {
1944
+ return this.send({ role, within: withinScope }, payload, meta);
1945
+ }
1946
+ /**
1947
+ * Broadcast a message to all agents
1948
+ */
1949
+ async broadcast(payload, meta) {
1950
+ return this.send({ broadcast: true }, payload, meta);
1951
+ }
1952
+ /**
1953
+ * Send a request and wait for a correlated response
1954
+ *
1955
+ * This is a higher-level pattern for request/response messaging.
1956
+ * A correlationId is automatically generated.
1957
+ */
1958
+ async request(to, payload, options) {
1959
+ const correlationId = `req-${Date.now()}-${Math.random().toString(36).slice(2)}`;
1960
+ const responseSub = await this.subscribe({
1961
+ // We'll filter in the handler since subscription filters don't support correlationId
1962
+ });
1963
+ try {
1964
+ await this.send(to, payload, {
1965
+ ...options?.meta,
1966
+ expectsResponse: true,
1967
+ correlationId
1968
+ });
1969
+ const timeout = options?.timeout ?? 3e4;
1970
+ const timeoutPromise = new Promise((_, reject) => {
1971
+ setTimeout(() => reject(new Error(`Request timed out after ${timeout}ms`)), timeout);
1972
+ });
1973
+ const responsePromise = (async () => {
1974
+ for await (const event of responseSub) {
1975
+ if (event.type === "message_delivered" && event.data && event.data.correlationId === correlationId) {
1976
+ return event.data.message;
1977
+ }
1978
+ }
1979
+ throw new Error("Subscription closed before response received");
1980
+ })();
1981
+ return await Promise.race([responsePromise, timeoutPromise]);
1982
+ } finally {
1983
+ await responseSub.unsubscribe();
1984
+ }
1985
+ }
1986
+ // ===========================================================================
1987
+ // Subscriptions
1988
+ // ===========================================================================
1989
+ /**
1990
+ * Subscribe to events
1991
+ */
1992
+ async subscribe(filter) {
1993
+ const params = {};
1994
+ if (filter) params.filter = filter;
1995
+ const result = await this.#connection.sendRequest(CORE_METHODS.SUBSCRIBE, params);
1996
+ const serverSupportsAck = this.#serverCapabilities?.streaming?.supportsAck === true;
1997
+ const sendAck = serverSupportsAck ? (ackParams) => {
1998
+ this.#connection.sendNotification(NOTIFICATION_METHODS.SUBSCRIBE_ACK, ackParams);
1999
+ } : void 0;
2000
+ const subscription = createSubscription(
2001
+ result.subscriptionId,
2002
+ () => this.unsubscribe(result.subscriptionId),
2003
+ { filter },
2004
+ sendAck
2005
+ );
2006
+ if (serverSupportsAck) {
2007
+ subscription._setServerSupportsAck(true);
2008
+ }
2009
+ this.#subscriptions.set(result.subscriptionId, subscription);
2010
+ if (this.#options.reconnection?.restoreSubscriptions !== false) {
2011
+ this.#subscriptionStates.set(result.subscriptionId, {
2012
+ filter,
2013
+ handlers: /* @__PURE__ */ new Set()
2014
+ });
2015
+ const originalPushEvent = subscription._pushEvent.bind(subscription);
2016
+ subscription._pushEvent = (event) => {
2017
+ const state = this.#subscriptionStates.get(result.subscriptionId);
2018
+ if (state && event.eventId) {
2019
+ state.lastEventId = event.eventId;
2020
+ }
2021
+ originalPushEvent(event);
2022
+ };
2023
+ }
2024
+ return subscription;
2025
+ }
2026
+ /**
2027
+ * Unsubscribe from events
2028
+ */
2029
+ async unsubscribe(subscriptionId) {
2030
+ const subscription = this.#subscriptions.get(subscriptionId);
2031
+ if (subscription) {
2032
+ subscription._close();
2033
+ this.#subscriptions.delete(subscriptionId);
2034
+ }
2035
+ this.#subscriptionStates.delete(subscriptionId);
2036
+ await this.#connection.sendRequest(CORE_METHODS.UNSUBSCRIBE, { subscriptionId });
2037
+ }
2038
+ // ===========================================================================
2039
+ // Event Replay
2040
+ // ===========================================================================
2041
+ /**
2042
+ * Replay historical events.
2043
+ *
2044
+ * Uses keyset pagination - pass the last eventId from the previous
2045
+ * response to get the next page.
2046
+ *
2047
+ * @example
2048
+ * ```typescript
2049
+ * // Replay all events from the last hour
2050
+ * const result = await client.replay({
2051
+ * fromTimestamp: Date.now() - 3600000,
2052
+ * filter: { eventTypes: ['agent.registered'] },
2053
+ * limit: 100
2054
+ * });
2055
+ *
2056
+ * // Paginate through results
2057
+ * let afterEventId: string | undefined;
2058
+ * do {
2059
+ * const page = await client.replay({ afterEventId, limit: 100 });
2060
+ * for (const item of page.events) {
2061
+ * console.log(item.eventId, item.event);
2062
+ * }
2063
+ * afterEventId = page.events.at(-1)?.eventId;
2064
+ * } while (page.hasMore);
2065
+ * ```
2066
+ */
2067
+ async replay(params = {}) {
2068
+ const limit = Math.min(params.limit ?? 100, 1e3);
2069
+ return this.#connection.sendRequest(
2070
+ CORE_METHODS.REPLAY,
2071
+ { ...params, limit }
2072
+ );
2073
+ }
2074
+ /**
2075
+ * Replay all events matching filter, handling pagination automatically.
2076
+ *
2077
+ * Returns an async generator for streaming through all results.
2078
+ *
2079
+ * @example
2080
+ * ```typescript
2081
+ * for await (const item of client.replayAll({
2082
+ * filter: { eventTypes: ['agent.registered'] }
2083
+ * })) {
2084
+ * console.log(item.eventId, item.event);
2085
+ * }
2086
+ * ```
2087
+ */
2088
+ async *replayAll(params = {}) {
2089
+ let afterEventId;
2090
+ let hasMore = true;
2091
+ while (hasMore) {
2092
+ const result = await this.replay({ ...params, afterEventId });
2093
+ for (const item of result.events) {
2094
+ yield item;
2095
+ }
2096
+ hasMore = result.hasMore;
2097
+ afterEventId = result.events.at(-1)?.eventId;
2098
+ if (result.events.length === 0) {
2099
+ break;
2100
+ }
2101
+ }
2102
+ }
2103
+ // ===========================================================================
2104
+ // Steering (requires canSteer capability)
2105
+ // ===========================================================================
2106
+ /**
2107
+ * Inject context into a running agent
2108
+ */
2109
+ async inject(agentId, content, delivery) {
2110
+ const params = { agentId, content };
2111
+ if (delivery) params.delivery = delivery;
2112
+ return this.#connection.sendRequest(STEERING_METHODS.INJECT, params);
2113
+ }
2114
+ // ===========================================================================
2115
+ // Lifecycle Control (requires canStop capability)
2116
+ // ===========================================================================
2117
+ /**
2118
+ * Request an agent to stop
2119
+ */
2120
+ async stopAgent(agentId, options) {
2121
+ return this.#connection.sendRequest(STATE_METHODS.AGENTS_STOP, {
2122
+ agentId,
2123
+ ...options
2124
+ });
2125
+ }
2126
+ /**
2127
+ * Suspend an agent
2128
+ */
2129
+ async suspendAgent(agentId, reason) {
2130
+ return this.#connection.sendRequest(STATE_METHODS.AGENTS_SUSPEND, {
2131
+ agentId,
2132
+ reason
2133
+ });
2134
+ }
2135
+ /**
2136
+ * Resume a suspended agent
2137
+ */
2138
+ async resumeAgent(agentId) {
2139
+ return this.#connection.sendRequest(STATE_METHODS.AGENTS_RESUME, { agentId });
2140
+ }
2141
+ // ===========================================================================
2142
+ // Reconnection
2143
+ // ===========================================================================
2144
+ /**
2145
+ * Current connection state
2146
+ */
2147
+ get state() {
2148
+ return this.#connection.state;
2149
+ }
2150
+ /**
2151
+ * Whether the connection is currently reconnecting
2152
+ */
2153
+ get isReconnecting() {
2154
+ return this.#isReconnecting;
2155
+ }
2156
+ /**
2157
+ * Register a handler for reconnection events.
2158
+ *
2159
+ * @param handler - Function called when reconnection events occur
2160
+ * @returns Unsubscribe function to remove the handler
2161
+ *
2162
+ * @example
2163
+ * ```typescript
2164
+ * const unsubscribe = client.onReconnection((event) => {
2165
+ * switch (event.type) {
2166
+ * case 'disconnected':
2167
+ * console.log('Connection lost');
2168
+ * break;
2169
+ * case 'reconnecting':
2170
+ * console.log(`Reconnecting, attempt ${event.attempt}`);
2171
+ * break;
2172
+ * case 'reconnected':
2173
+ * console.log('Reconnected successfully');
2174
+ * break;
2175
+ * case 'reconnectFailed':
2176
+ * console.log('Failed to reconnect:', event.error);
2177
+ * break;
2178
+ * }
2179
+ * });
2180
+ * ```
2181
+ */
2182
+ onReconnection(handler) {
2183
+ this.#reconnectionHandlers.add(handler);
2184
+ return () => this.#reconnectionHandlers.delete(handler);
2185
+ }
2186
+ /**
2187
+ * Register a handler for connection state changes.
2188
+ *
2189
+ * @param handler - Function called when state changes
2190
+ * @returns Unsubscribe function to remove the handler
2191
+ */
2192
+ onStateChange(handler) {
2193
+ return this.#connection.onStateChange(handler);
2194
+ }
2195
+ // ===========================================================================
2196
+ // Internal
2197
+ // ===========================================================================
2198
+ /**
2199
+ * Handle incoming notifications
2200
+ */
2201
+ async #handleNotification(method, params) {
2202
+ switch (method) {
2203
+ case NOTIFICATION_METHODS.EVENT: {
2204
+ const eventParams = params;
2205
+ const subscription = this.#subscriptions.get(eventParams.subscriptionId);
2206
+ if (subscription) {
2207
+ subscription._pushEvent(eventParams);
2208
+ } else {
2209
+ console.warn("MAP: Event for unknown subscription:", eventParams.subscriptionId);
2210
+ }
2211
+ break;
2212
+ }
2213
+ case NOTIFICATION_METHODS.MESSAGE: {
2214
+ break;
2215
+ }
2216
+ default:
2217
+ console.warn("MAP: Unknown notification:", method);
2218
+ }
2219
+ }
2220
+ /**
2221
+ * Emit a reconnection event to all registered handlers
2222
+ */
2223
+ #emitReconnectionEvent(event) {
2224
+ for (const handler of this.#reconnectionHandlers) {
2225
+ try {
2226
+ handler(event);
2227
+ } catch (error) {
2228
+ console.error("MAP: Reconnection event handler error:", error);
2229
+ }
2230
+ }
2231
+ }
2232
+ /**
2233
+ * Handle disconnect when auto-reconnect is enabled
2234
+ */
2235
+ async #handleDisconnect() {
2236
+ this.#isReconnecting = true;
2237
+ this.#connected = false;
2238
+ this.#emitReconnectionEvent({ type: "disconnected" });
2239
+ try {
2240
+ await this.#attemptReconnect();
2241
+ } catch (error) {
2242
+ this.#isReconnecting = false;
2243
+ this.#emitReconnectionEvent({
2244
+ type: "reconnectFailed",
2245
+ error: error instanceof Error ? error : new Error(String(error))
2246
+ });
2247
+ }
2248
+ }
2249
+ /**
2250
+ * Attempt to reconnect with retry logic
2251
+ */
2252
+ async #attemptReconnect() {
2253
+ const options = this.#options.reconnection;
2254
+ const createStream = this.#options.createStream;
2255
+ const retryPolicy = {
2256
+ maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY.maxRetries,
2257
+ baseDelayMs: options.baseDelayMs ?? DEFAULT_RETRY_POLICY.baseDelayMs,
2258
+ maxDelayMs: options.maxDelayMs ?? DEFAULT_RETRY_POLICY.maxDelayMs,
2259
+ jitter: options.jitter ?? DEFAULT_RETRY_POLICY.jitter
2260
+ };
2261
+ await withRetry(
2262
+ async () => {
2263
+ const newStream = await createStream();
2264
+ await this.#connection.reconnect(newStream);
2265
+ const connectResult = await this.connect(this.#lastConnectOptions);
2266
+ this.#sessionId = connectResult.sessionId;
2267
+ this.#serverCapabilities = connectResult.capabilities;
2268
+ },
2269
+ retryPolicy,
2270
+ {
2271
+ onRetry: (state) => {
2272
+ this.#emitReconnectionEvent({
2273
+ type: "reconnecting",
2274
+ attempt: state.attempt,
2275
+ delay: state.nextDelayMs,
2276
+ error: state.lastError
2277
+ });
2278
+ }
2279
+ }
2280
+ );
2281
+ this.#isReconnecting = false;
2282
+ this.#emitReconnectionEvent({ type: "reconnected" });
2283
+ if (options.restoreSubscriptions !== false) {
2284
+ await this.#restoreSubscriptions();
2285
+ }
2286
+ }
2287
+ /**
2288
+ * Restore subscriptions after reconnection
2289
+ */
2290
+ async #restoreSubscriptions() {
2291
+ const options = this.#options.reconnection;
2292
+ const subscriptionEntries = Array.from(this.#subscriptionStates.entries());
2293
+ this.#subscriptions.clear();
2294
+ this.#subscriptionStates.clear();
2295
+ for (const [oldId, state] of subscriptionEntries) {
2296
+ try {
2297
+ const newSubscription = await this.subscribe(state.filter);
2298
+ const newId = newSubscription.id;
2299
+ if (options.replayOnRestore !== false && state.lastEventId) {
2300
+ const maxEvents = options.maxReplayEventsPerSubscription ?? 1e3;
2301
+ try {
2302
+ let replayedCount = 0;
2303
+ let afterEventId = state.lastEventId;
2304
+ let hasMore = true;
2305
+ while (hasMore && replayedCount < maxEvents) {
2306
+ const result = await this.replay({
2307
+ afterEventId,
2308
+ filter: state.filter,
2309
+ limit: Math.min(100, maxEvents - replayedCount)
2310
+ });
2311
+ for (const replayedEvent of result.events) {
2312
+ if (replayedCount >= maxEvents) break;
2313
+ newSubscription._pushEvent({
2314
+ subscriptionId: newId,
2315
+ sequenceNumber: replayedCount + 1,
2316
+ eventId: replayedEvent.eventId,
2317
+ timestamp: replayedEvent.timestamp,
2318
+ event: replayedEvent.event
2319
+ });
2320
+ replayedCount++;
2321
+ }
2322
+ hasMore = result.hasMore;
2323
+ afterEventId = result.events.at(-1)?.eventId;
2324
+ if (result.events.length === 0) {
2325
+ break;
2326
+ }
2327
+ }
2328
+ } catch (replayError) {
2329
+ console.warn("MAP: Failed to replay events for subscription:", oldId, replayError);
2330
+ }
2331
+ }
2332
+ this.#emitReconnectionEvent({
2333
+ type: "subscriptionRestored",
2334
+ subscriptionId: oldId,
2335
+ newSubscriptionId: newId
2336
+ });
2337
+ } catch (error) {
2338
+ this.#emitReconnectionEvent({
2339
+ type: "subscriptionRestoreFailed",
2340
+ subscriptionId: oldId,
2341
+ error: error instanceof Error ? error : new Error(String(error))
2342
+ });
2343
+ }
2344
+ }
2345
+ }
2346
+ };
2347
+
2348
+ // src/connection/agent.ts
2349
+ var AgentConnection = class {
2350
+ #connection;
2351
+ #subscriptions = /* @__PURE__ */ new Map();
2352
+ #options;
2353
+ #messageHandlers = /* @__PURE__ */ new Set();
2354
+ #reconnectionHandlers = /* @__PURE__ */ new Set();
2355
+ #scopeMemberships = /* @__PURE__ */ new Set();
2356
+ #agentId = null;
2357
+ #sessionId = null;
2358
+ #serverCapabilities = null;
2359
+ #currentState = "registered";
2360
+ #connected = false;
2361
+ #lastConnectOptions;
2362
+ #isReconnecting = false;
2363
+ constructor(stream, options = {}) {
2364
+ this.#connection = new BaseConnection(stream, options);
2365
+ this.#options = options;
2366
+ this.#connection.setNotificationHandler(this.#handleNotification.bind(this));
2367
+ if (options.reconnection?.enabled && options.createStream) {
2368
+ this.#connection.onStateChange((newState) => {
2369
+ if (newState === "closed" && this.#connected && !this.#isReconnecting) {
2370
+ void this.#handleDisconnect();
2371
+ }
2372
+ });
2373
+ }
2374
+ }
2375
+ // ===========================================================================
2376
+ // Connection Lifecycle
2377
+ // ===========================================================================
2378
+ /**
2379
+ * Connect and register with the MAP system
2380
+ */
2381
+ async connect(options) {
2382
+ const connectParams = {
2383
+ protocolVersion: PROTOCOL_VERSION,
2384
+ participantType: "agent",
2385
+ participantId: options?.agentId,
2386
+ name: this.#options.name,
2387
+ capabilities: this.#options.capabilities,
2388
+ auth: options?.auth
2389
+ };
2390
+ const connectResult = await this.#connection.sendRequest(CORE_METHODS.CONNECT, connectParams);
2391
+ this.#sessionId = connectResult.sessionId;
2392
+ this.#serverCapabilities = connectResult.capabilities;
2393
+ this.#connected = true;
2394
+ this.#lastConnectOptions = options;
2395
+ const registerParams = {
2396
+ agentId: options?.agentId,
2397
+ name: this.#options.name,
2398
+ role: this.#options.role,
2399
+ parent: this.#options.parent,
2400
+ scopes: this.#options.scopes,
2401
+ visibility: this.#options.visibility,
2402
+ capabilities: this.#options.capabilities
2403
+ };
2404
+ const registerResult = await this.#connection.sendRequest(LIFECYCLE_METHODS.AGENTS_REGISTER, registerParams);
2405
+ this.#agentId = registerResult.agent.id;
2406
+ this.#currentState = registerResult.agent.state;
2407
+ this.#connection._transitionTo("connected");
2408
+ return { connection: connectResult, agent: registerResult.agent };
2409
+ }
2410
+ /**
2411
+ * Disconnect from the MAP system
2412
+ */
2413
+ async disconnect(reason) {
2414
+ if (!this.#connected) return;
2415
+ try {
2416
+ if (this.#agentId) {
2417
+ await this.#connection.sendRequest(LIFECYCLE_METHODS.AGENTS_UNREGISTER, {
2418
+ agentId: this.#agentId,
2419
+ reason
2420
+ });
2421
+ }
2422
+ await this.#connection.sendRequest(
2423
+ CORE_METHODS.DISCONNECT,
2424
+ reason ? { reason } : void 0
2425
+ );
2426
+ } finally {
2427
+ for (const subscription of this.#subscriptions.values()) {
2428
+ subscription._close();
2429
+ }
2430
+ this.#subscriptions.clear();
2431
+ await this.#connection.close();
2432
+ this.#connected = false;
2433
+ }
2434
+ }
2435
+ /**
2436
+ * Whether the agent is connected
2437
+ */
2438
+ get isConnected() {
2439
+ return this.#connected && !this.#connection.isClosed;
2440
+ }
2441
+ /**
2442
+ * This agent's ID
2443
+ */
2444
+ get agentId() {
2445
+ return this.#agentId;
2446
+ }
2447
+ /**
2448
+ * Current session ID
2449
+ */
2450
+ get sessionId() {
2451
+ return this.#sessionId;
2452
+ }
2453
+ /**
2454
+ * Server capabilities
2455
+ */
2456
+ get serverCapabilities() {
2457
+ return this.#serverCapabilities;
2458
+ }
2459
+ /**
2460
+ * Current agent state
2461
+ */
2462
+ get state() {
2463
+ return this.#currentState;
2464
+ }
2465
+ /**
2466
+ * AbortSignal that triggers when the connection closes
2467
+ */
2468
+ get signal() {
2469
+ return this.#connection.signal;
2470
+ }
2471
+ /**
2472
+ * Promise that resolves when the connection closes
2473
+ */
2474
+ get closed() {
2475
+ return this.#connection.closed;
2476
+ }
2477
+ // ===========================================================================
2478
+ // Message Handling
2479
+ // ===========================================================================
2480
+ /**
2481
+ * Register a handler for incoming messages
2482
+ */
2483
+ onMessage(handler) {
2484
+ this.#messageHandlers.add(handler);
2485
+ return this;
2486
+ }
2487
+ /**
2488
+ * Remove a message handler
2489
+ */
2490
+ offMessage(handler) {
2491
+ this.#messageHandlers.delete(handler);
2492
+ return this;
2493
+ }
2494
+ // ===========================================================================
2495
+ // State Management
2496
+ // ===========================================================================
2497
+ /**
2498
+ * Update this agent's state
2499
+ */
2500
+ async updateState(state) {
2501
+ if (!this.#agentId) {
2502
+ throw new Error("Agent not registered");
2503
+ }
2504
+ const result = await this.#connection.sendRequest(STATE_METHODS.AGENTS_UPDATE, {
2505
+ agentId: this.#agentId,
2506
+ state
2507
+ });
2508
+ this.#currentState = result.agent.state;
2509
+ return result.agent;
2510
+ }
2511
+ /**
2512
+ * Update this agent's metadata
2513
+ */
2514
+ async updateMetadata(metadata) {
2515
+ if (!this.#agentId) {
2516
+ throw new Error("Agent not registered");
2517
+ }
2518
+ const result = await this.#connection.sendRequest(STATE_METHODS.AGENTS_UPDATE, {
2519
+ agentId: this.#agentId,
2520
+ metadata
2521
+ });
2522
+ return result.agent;
2523
+ }
2524
+ /**
2525
+ * Mark this agent as busy
2526
+ */
2527
+ async busy() {
2528
+ return this.updateState("busy");
2529
+ }
2530
+ /**
2531
+ * Mark this agent as idle
2532
+ */
2533
+ async idle() {
2534
+ return this.updateState("idle");
2535
+ }
2536
+ /**
2537
+ * Mark this agent as done/stopped
2538
+ */
2539
+ async done(result) {
2540
+ if (!this.#agentId) {
2541
+ throw new Error("Agent not registered");
2542
+ }
2543
+ await this.updateState("stopped");
2544
+ if (result) {
2545
+ await this.updateMetadata({
2546
+ exitCode: result.exitCode,
2547
+ exitReason: result.exitReason
2548
+ });
2549
+ }
2550
+ }
2551
+ // ===========================================================================
2552
+ // Child Agent Management
2553
+ // ===========================================================================
2554
+ /**
2555
+ * Spawn a child agent
2556
+ */
2557
+ async spawn(options) {
2558
+ if (!this.#agentId) {
2559
+ throw new Error("Agent not registered");
2560
+ }
2561
+ const params = {
2562
+ ...options,
2563
+ parent: this.#agentId
2564
+ };
2565
+ return this.#connection.sendRequest(LIFECYCLE_METHODS.AGENTS_SPAWN, params);
2566
+ }
2567
+ // ===========================================================================
2568
+ // Messaging
2569
+ // ===========================================================================
2570
+ /**
2571
+ * Send a message to an address
2572
+ */
2573
+ async send(to, payload, meta) {
2574
+ const params = { to };
2575
+ if (payload !== void 0) params.payload = payload;
2576
+ if (meta) params.meta = meta;
2577
+ return this.#connection.sendRequest(CORE_METHODS.SEND, params);
2578
+ }
2579
+ /**
2580
+ * Send a message to the parent agent
2581
+ */
2582
+ async sendToParent(payload, meta) {
2583
+ return this.send({ parent: true }, payload, {
2584
+ ...meta,
2585
+ relationship: "child-to-parent"
2586
+ });
2587
+ }
2588
+ /**
2589
+ * Send a message to child agents
2590
+ */
2591
+ async sendToChildren(payload, meta) {
2592
+ return this.send({ children: true }, payload, {
2593
+ ...meta,
2594
+ relationship: "parent-to-child"
2595
+ });
2596
+ }
2597
+ /**
2598
+ * Send a message to a specific agent
2599
+ */
2600
+ async sendToAgent(agentId, payload, meta) {
2601
+ return this.send({ agent: agentId }, payload, meta);
2602
+ }
2603
+ /**
2604
+ * Send a message to all agents in a scope
2605
+ */
2606
+ async sendToScope(scopeId, payload, meta) {
2607
+ return this.send({ scope: scopeId }, payload, meta);
2608
+ }
2609
+ /**
2610
+ * Send a message to sibling agents
2611
+ */
2612
+ async sendToSiblings(payload, meta) {
2613
+ return this.send({ siblings: true }, payload, {
2614
+ ...meta,
2615
+ relationship: "peer"
2616
+ });
2617
+ }
2618
+ /**
2619
+ * Reply to a message (uses correlationId from original)
2620
+ */
2621
+ async reply(originalMessage, payload, meta) {
2622
+ return this.send({ agent: originalMessage.from }, payload, {
2623
+ ...meta,
2624
+ correlationId: originalMessage.meta?.correlationId ?? originalMessage.id,
2625
+ isResult: true
2626
+ });
2627
+ }
2628
+ // ===========================================================================
2629
+ // Scope Management
2630
+ // ===========================================================================
2631
+ /**
2632
+ * Create a new scope
2633
+ */
2634
+ async createScope(options) {
2635
+ const result = await this.#connection.sendRequest(SCOPE_METHODS.SCOPES_CREATE, options);
2636
+ return result.scope;
2637
+ }
2638
+ /**
2639
+ * Join a scope
2640
+ */
2641
+ async joinScope(scopeId) {
2642
+ if (!this.#agentId) {
2643
+ throw new Error("Agent not registered");
2644
+ }
2645
+ const result = await this.#connection.sendRequest(SCOPE_METHODS.SCOPES_JOIN, {
2646
+ scopeId,
2647
+ agentId: this.#agentId
2648
+ });
2649
+ this.#scopeMemberships.add(scopeId);
2650
+ return result;
2651
+ }
2652
+ /**
2653
+ * Leave a scope
2654
+ */
2655
+ async leaveScope(scopeId) {
2656
+ if (!this.#agentId) {
2657
+ throw new Error("Agent not registered");
2658
+ }
2659
+ const result = await this.#connection.sendRequest(SCOPE_METHODS.SCOPES_LEAVE, {
2660
+ scopeId,
2661
+ agentId: this.#agentId
2662
+ });
2663
+ this.#scopeMemberships.delete(scopeId);
2664
+ return result;
2665
+ }
2666
+ // ===========================================================================
2667
+ // Subscriptions
2668
+ // ===========================================================================
2669
+ /**
2670
+ * Subscribe to events
2671
+ */
2672
+ async subscribe(filter) {
2673
+ const params = {};
2674
+ if (filter) params.filter = filter;
2675
+ const result = await this.#connection.sendRequest(CORE_METHODS.SUBSCRIBE, params);
2676
+ const subscription = createSubscription(
2677
+ result.subscriptionId,
2678
+ () => this.unsubscribe(result.subscriptionId),
2679
+ { filter }
2680
+ );
2681
+ this.#subscriptions.set(result.subscriptionId, subscription);
2682
+ return subscription;
2683
+ }
2684
+ /**
2685
+ * Unsubscribe from events
2686
+ */
2687
+ async unsubscribe(subscriptionId) {
2688
+ const subscription = this.#subscriptions.get(subscriptionId);
2689
+ if (subscription) {
2690
+ subscription._close();
2691
+ this.#subscriptions.delete(subscriptionId);
2692
+ }
2693
+ await this.#connection.sendRequest(CORE_METHODS.UNSUBSCRIBE, { subscriptionId });
2694
+ }
2695
+ // ===========================================================================
2696
+ // Reconnection
2697
+ // ===========================================================================
2698
+ /**
2699
+ * Current connection state
2700
+ */
2701
+ get connectionState() {
2702
+ return this.#connection.state;
2703
+ }
2704
+ /**
2705
+ * Whether the connection is currently reconnecting
2706
+ */
2707
+ get isReconnecting() {
2708
+ return this.#isReconnecting;
2709
+ }
2710
+ /**
2711
+ * Register a handler for reconnection events.
2712
+ *
2713
+ * @param handler - Function called when reconnection events occur
2714
+ * @returns Unsubscribe function to remove the handler
2715
+ */
2716
+ onReconnection(handler) {
2717
+ this.#reconnectionHandlers.add(handler);
2718
+ return () => this.#reconnectionHandlers.delete(handler);
2719
+ }
2720
+ /**
2721
+ * Register a handler for connection state changes.
2722
+ *
2723
+ * @param handler - Function called when state changes
2724
+ * @returns Unsubscribe function to remove the handler
2725
+ */
2726
+ onStateChange(handler) {
2727
+ return this.#connection.onStateChange(handler);
2728
+ }
2729
+ // ===========================================================================
2730
+ // Internal
2731
+ // ===========================================================================
2732
+ /**
2733
+ * Handle incoming notifications
2734
+ */
2735
+ async #handleNotification(method, params) {
2736
+ switch (method) {
2737
+ case NOTIFICATION_METHODS.EVENT: {
2738
+ const eventParams = params;
2739
+ const subscription = this.#subscriptions.get(eventParams.subscriptionId);
2740
+ if (subscription) {
2741
+ subscription._pushEvent(eventParams);
2742
+ }
2743
+ break;
2744
+ }
2745
+ case NOTIFICATION_METHODS.MESSAGE: {
2746
+ const messageParams = params;
2747
+ for (const handler of this.#messageHandlers) {
2748
+ try {
2749
+ await handler(messageParams.message);
2750
+ } catch (error) {
2751
+ console.error("MAP: Message handler error:", error);
2752
+ }
2753
+ }
2754
+ break;
2755
+ }
2756
+ default:
2757
+ console.warn("MAP: Unknown notification:", method);
2758
+ }
2759
+ }
2760
+ /**
2761
+ * Emit a reconnection event to all registered handlers
2762
+ */
2763
+ #emitReconnectionEvent(event) {
2764
+ for (const handler of this.#reconnectionHandlers) {
2765
+ try {
2766
+ handler(event);
2767
+ } catch (error) {
2768
+ console.error("MAP: Reconnection event handler error:", error);
2769
+ }
2770
+ }
2771
+ }
2772
+ /**
2773
+ * Handle disconnect when auto-reconnect is enabled
2774
+ */
2775
+ async #handleDisconnect() {
2776
+ this.#isReconnecting = true;
2777
+ this.#connected = false;
2778
+ this.#emitReconnectionEvent({ type: "disconnected" });
2779
+ try {
2780
+ await this.#attemptReconnect();
2781
+ } catch (error) {
2782
+ this.#isReconnecting = false;
2783
+ this.#emitReconnectionEvent({
2784
+ type: "reconnectFailed",
2785
+ error: error instanceof Error ? error : new Error(String(error))
2786
+ });
2787
+ }
2788
+ }
2789
+ /**
2790
+ * Attempt to reconnect with retry logic
2791
+ */
2792
+ async #attemptReconnect() {
2793
+ const options = this.#options.reconnection;
2794
+ const createStream = this.#options.createStream;
2795
+ const retryPolicy = {
2796
+ maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY.maxRetries,
2797
+ baseDelayMs: options.baseDelayMs ?? DEFAULT_RETRY_POLICY.baseDelayMs,
2798
+ maxDelayMs: options.maxDelayMs ?? DEFAULT_RETRY_POLICY.maxDelayMs,
2799
+ jitter: options.jitter ?? DEFAULT_RETRY_POLICY.jitter
2800
+ };
2801
+ const scopesToRestore = Array.from(this.#scopeMemberships);
2802
+ await withRetry(
2803
+ async () => {
2804
+ const newStream = await createStream();
2805
+ await this.#connection.reconnect(newStream);
2806
+ const result = await this.connect({
2807
+ agentId: this.#agentId ?? this.#lastConnectOptions?.agentId,
2808
+ auth: this.#lastConnectOptions?.auth
2809
+ });
2810
+ this.#agentId = result.agent.id;
2811
+ this.#sessionId = result.connection.sessionId;
2812
+ this.#serverCapabilities = result.connection.capabilities;
2813
+ this.#currentState = result.agent.state;
2814
+ },
2815
+ retryPolicy,
2816
+ {
2817
+ onRetry: (state) => {
2818
+ this.#emitReconnectionEvent({
2819
+ type: "reconnecting",
2820
+ attempt: state.attempt,
2821
+ delay: state.nextDelayMs,
2822
+ error: state.lastError
2823
+ });
2824
+ }
2825
+ }
2826
+ );
2827
+ this.#isReconnecting = false;
2828
+ this.#emitReconnectionEvent({ type: "reconnected" });
2829
+ if (options.restoreScopeMemberships !== false) {
2830
+ await this.#restoreScopeMemberships(scopesToRestore);
2831
+ }
2832
+ }
2833
+ /**
2834
+ * Restore scope memberships after reconnection
2835
+ */
2836
+ async #restoreScopeMemberships(scopes) {
2837
+ this.#scopeMemberships.clear();
2838
+ for (const scopeId of scopes) {
2839
+ try {
2840
+ await this.joinScope(scopeId);
2841
+ } catch (error) {
2842
+ console.warn("MAP: Failed to restore scope membership:", scopeId, error);
2843
+ }
2844
+ }
2845
+ }
2846
+ };
2847
+
2848
+ // src/federation/envelope.ts
2849
+ function createFederationEnvelope(payload, sourceSystem, targetSystem, options) {
2850
+ return {
2851
+ payload,
2852
+ federation: {
2853
+ sourceSystem,
2854
+ targetSystem,
2855
+ hopCount: 0,
2856
+ maxHops: options?.maxHops,
2857
+ path: options?.trackPath ? [sourceSystem] : void 0,
2858
+ originTimestamp: Date.now(),
2859
+ correlationId: options?.correlationId
2860
+ }
2861
+ };
2862
+ }
2863
+ function processFederationEnvelope(envelope, config) {
2864
+ const { federation } = envelope;
2865
+ const maxHops = federation.maxHops ?? config.maxHops ?? 10;
2866
+ if (federation.hopCount >= maxHops) {
2867
+ return {
2868
+ success: false,
2869
+ errorCode: ERROR_CODES.FEDERATION_MAX_HOPS_EXCEEDED,
2870
+ errorMessage: `Message exceeded maximum hop count of ${maxHops}`
2871
+ };
2872
+ }
2873
+ if (federation.path?.includes(config.systemId)) {
2874
+ return {
2875
+ success: false,
2876
+ errorCode: ERROR_CODES.FEDERATION_LOOP_DETECTED,
2877
+ errorMessage: `Loop detected: message already visited ${config.systemId}`
2878
+ };
2879
+ }
2880
+ if (config.allowedSources && !config.allowedSources.includes(federation.sourceSystem)) {
2881
+ return {
2882
+ success: false,
2883
+ errorCode: ERROR_CODES.FEDERATION_ROUTE_REJECTED,
2884
+ errorMessage: `Source system ${federation.sourceSystem} not in allowed sources`
2885
+ };
2886
+ }
2887
+ if (config.allowedTargets && !config.allowedTargets.includes(federation.targetSystem)) {
2888
+ return {
2889
+ success: false,
2890
+ errorCode: ERROR_CODES.FEDERATION_ROUTE_REJECTED,
2891
+ errorMessage: `Target system ${federation.targetSystem} not in allowed targets`
2892
+ };
2893
+ }
2894
+ return {
2895
+ success: true,
2896
+ envelope: {
2897
+ payload: envelope.payload,
2898
+ federation: {
2899
+ ...federation,
2900
+ hopCount: federation.hopCount + 1,
2901
+ path: config.trackPath ? [...federation.path ?? [], config.systemId] : federation.path
2902
+ }
2903
+ }
2904
+ };
2905
+ }
2906
+ function isEnvelopeAtDestination(envelope, currentSystemId) {
2907
+ return envelope.federation.targetSystem === currentSystemId;
2908
+ }
2909
+ function unwrapEnvelope(envelope) {
2910
+ return envelope.payload;
2911
+ }
2912
+ function getEnvelopeRoutingInfo(envelope) {
2913
+ const { federation } = envelope;
2914
+ return {
2915
+ source: federation.sourceSystem,
2916
+ target: federation.targetSystem,
2917
+ hops: federation.hopCount,
2918
+ path: federation.path,
2919
+ age: Date.now() - federation.originTimestamp,
2920
+ correlationId: federation.correlationId
2921
+ };
2922
+ }
2923
+ function isValidEnvelope(obj) {
2924
+ if (!obj || typeof obj !== "object") return false;
2925
+ const envelope = obj;
2926
+ if (!("payload" in envelope) || !("federation" in envelope)) return false;
2927
+ const federation = envelope.federation;
2928
+ if (!federation || typeof federation !== "object") return false;
2929
+ return typeof federation.sourceSystem === "string" && typeof federation.targetSystem === "string" && typeof federation.hopCount === "number" && typeof federation.originTimestamp === "number";
2930
+ }
2931
+ function withPayload(envelope, newPayload) {
2932
+ return {
2933
+ payload: newPayload,
2934
+ federation: envelope.federation
2935
+ };
2936
+ }
2937
+
2938
+ // src/federation/buffer.ts
2939
+ var DEFAULT_CONFIG = {
2940
+ enabled: true,
2941
+ maxMessages: 1e3,
2942
+ maxBytes: 10 * 1024 * 1024,
2943
+ // 10MB
2944
+ retentionMs: 60 * 60 * 1e3,
2945
+ // 1 hour
2946
+ overflowStrategy: "drop-oldest"
2947
+ };
2948
+ var FederationOutageBuffer = class {
2949
+ #config;
2950
+ #buffers = /* @__PURE__ */ new Map();
2951
+ constructor(config) {
2952
+ this.#config = { ...DEFAULT_CONFIG, ...config };
2953
+ }
2954
+ /**
2955
+ * Whether buffering is enabled.
2956
+ */
2957
+ get enabled() {
2958
+ return this.#config.enabled;
2959
+ }
2960
+ /**
2961
+ * Get the configuration.
2962
+ */
2963
+ get config() {
2964
+ return this.#config;
2965
+ }
2966
+ /**
2967
+ * Enqueue a message for a peer.
2968
+ *
2969
+ * @param peerId - Target peer system ID
2970
+ * @param envelope - Message envelope to buffer
2971
+ * @returns true if message was buffered, false if rejected
2972
+ */
2973
+ enqueue(peerId, envelope) {
2974
+ if (!this.#config.enabled) return false;
2975
+ let buffer = this.#buffers.get(peerId);
2976
+ if (!buffer) {
2977
+ buffer = { messages: [], totalEnqueued: 0, totalDropped: 0, totalBytes: 0 };
2978
+ this.#buffers.set(peerId, buffer);
2979
+ }
2980
+ this.#evictExpired(buffer);
2981
+ const messageSize = this.#estimateSize(envelope);
2982
+ while (buffer.totalBytes + messageSize > this.#config.maxBytes && buffer.messages.length > 0) {
2983
+ const removed = buffer.messages.shift();
2984
+ buffer.totalBytes -= removed.size;
2985
+ buffer.totalDropped++;
2986
+ }
2987
+ if (buffer.messages.length >= this.#config.maxMessages) {
2988
+ switch (this.#config.overflowStrategy) {
2989
+ case "drop-oldest": {
2990
+ const removed = buffer.messages.shift();
2991
+ buffer.totalBytes -= removed.size;
2992
+ buffer.totalDropped++;
2993
+ break;
2994
+ }
2995
+ case "drop-newest":
2996
+ buffer.totalDropped++;
2997
+ return false;
2998
+ case "reject":
2999
+ return false;
3000
+ }
3001
+ }
3002
+ buffer.messages.push({
3003
+ envelope,
3004
+ enqueuedAt: Date.now(),
3005
+ size: messageSize
3006
+ });
3007
+ buffer.totalEnqueued++;
3008
+ buffer.totalBytes += messageSize;
3009
+ return true;
3010
+ }
3011
+ /**
3012
+ * Drain all buffered messages for a peer.
3013
+ *
3014
+ * Returns messages in FIFO order and clears the buffer.
3015
+ *
3016
+ * @param peerId - Target peer system ID
3017
+ * @returns Array of buffered envelopes
3018
+ */
3019
+ drain(peerId) {
3020
+ const buffer = this.#buffers.get(peerId);
3021
+ if (!buffer) return [];
3022
+ this.#evictExpired(buffer);
3023
+ const messages = buffer.messages.map((m) => m.envelope);
3024
+ buffer.messages = [];
3025
+ buffer.totalBytes = 0;
3026
+ return messages;
3027
+ }
3028
+ /**
3029
+ * Peek at buffered messages without removing them.
3030
+ *
3031
+ * @param peerId - Target peer system ID
3032
+ * @returns Array of buffered envelopes (still in buffer)
3033
+ */
3034
+ peek(peerId) {
3035
+ const buffer = this.#buffers.get(peerId);
3036
+ if (!buffer) return [];
3037
+ this.#evictExpired(buffer);
3038
+ return buffer.messages.map((m) => m.envelope);
3039
+ }
3040
+ /**
3041
+ * Get statistics for all peer buffers.
3042
+ *
3043
+ * @returns Map of peer ID to buffer stats
3044
+ */
3045
+ stats() {
3046
+ const result = /* @__PURE__ */ new Map();
3047
+ const now = Date.now();
3048
+ for (const [peerId, buffer] of this.#buffers) {
3049
+ this.#evictExpired(buffer);
3050
+ const oldestAge = buffer.messages.length > 0 ? now - buffer.messages[0].enqueuedAt : 0;
3051
+ result.set(peerId, {
3052
+ count: buffer.messages.length,
3053
+ oldestAge,
3054
+ totalEnqueued: buffer.totalEnqueued,
3055
+ totalDropped: buffer.totalDropped,
3056
+ totalBytes: buffer.totalBytes
3057
+ });
3058
+ }
3059
+ return result;
3060
+ }
3061
+ /**
3062
+ * Get count for a specific peer.
3063
+ *
3064
+ * @param peerId - Target peer system ID
3065
+ * @returns Number of buffered messages
3066
+ */
3067
+ count(peerId) {
3068
+ const buffer = this.#buffers.get(peerId);
3069
+ if (!buffer) return 0;
3070
+ this.#evictExpired(buffer);
3071
+ return buffer.messages.length;
3072
+ }
3073
+ /**
3074
+ * Check if buffer has messages for a peer.
3075
+ *
3076
+ * @param peerId - Target peer system ID
3077
+ * @returns true if there are buffered messages
3078
+ */
3079
+ has(peerId) {
3080
+ return this.count(peerId) > 0;
3081
+ }
3082
+ /**
3083
+ * Clear buffer for a specific peer.
3084
+ *
3085
+ * @param peerId - Target peer system ID
3086
+ */
3087
+ clear(peerId) {
3088
+ this.#buffers.delete(peerId);
3089
+ }
3090
+ /**
3091
+ * Clear all buffers.
3092
+ */
3093
+ clearAll() {
3094
+ this.#buffers.clear();
3095
+ }
3096
+ /**
3097
+ * Get list of peers with buffered messages.
3098
+ *
3099
+ * @returns Array of peer IDs
3100
+ */
3101
+ peers() {
3102
+ const result = [];
3103
+ for (const [peerId, buffer] of this.#buffers) {
3104
+ this.#evictExpired(buffer);
3105
+ if (buffer.messages.length > 0) {
3106
+ result.push(peerId);
3107
+ }
3108
+ }
3109
+ return result;
3110
+ }
3111
+ /**
3112
+ * Evict expired messages from a buffer.
3113
+ */
3114
+ #evictExpired(buffer) {
3115
+ const cutoff = Date.now() - this.#config.retentionMs;
3116
+ let removed = 0;
3117
+ let bytesRemoved = 0;
3118
+ while (buffer.messages.length > 0 && buffer.messages[0].enqueuedAt < cutoff) {
3119
+ const msg = buffer.messages.shift();
3120
+ bytesRemoved += msg.size;
3121
+ removed++;
3122
+ }
3123
+ buffer.totalDropped += removed;
3124
+ buffer.totalBytes -= bytesRemoved;
3125
+ }
3126
+ /**
3127
+ * Estimate the size of an envelope in bytes.
3128
+ */
3129
+ #estimateSize(envelope) {
3130
+ try {
3131
+ return JSON.stringify(envelope).length * 2;
3132
+ } catch {
3133
+ return 1024;
3134
+ }
3135
+ }
3136
+ };
3137
+
3138
+ // src/connection/gateway.ts
3139
+ var GatewayConnection = class {
3140
+ #connection;
3141
+ #options;
3142
+ #connectedSystems = /* @__PURE__ */ new Map();
3143
+ #reconnectionHandlers = /* @__PURE__ */ new Set();
3144
+ #outageBuffer;
3145
+ #lastSyncTimestamps = /* @__PURE__ */ new Map();
3146
+ #sessionId = null;
3147
+ #serverCapabilities = null;
3148
+ #connected = false;
3149
+ #isReconnecting = false;
3150
+ #lastConnectOptions;
3151
+ constructor(stream, options = {}) {
3152
+ this.#connection = new BaseConnection(stream, options);
3153
+ this.#options = options;
3154
+ this.#outageBuffer = options.buffer?.enabled ? new FederationOutageBuffer(options.buffer) : null;
3155
+ if (options.reconnection?.enabled && options.createStream) {
3156
+ this.#connection.onStateChange((newState) => {
3157
+ if (newState === "closed" && this.#connected && !this.#isReconnecting) {
3158
+ void this.#handleDisconnect();
3159
+ }
3160
+ });
3161
+ }
3162
+ }
3163
+ // ===========================================================================
3164
+ // Connection Lifecycle
3165
+ // ===========================================================================
3166
+ /**
3167
+ * Connect to the local MAP system
3168
+ */
3169
+ async connect(options) {
3170
+ const params = {
3171
+ protocolVersion: PROTOCOL_VERSION,
3172
+ participantType: "gateway",
3173
+ name: this.#options.name,
3174
+ capabilities: this.#options.capabilities,
3175
+ auth: options?.auth
3176
+ };
3177
+ const result = await this.#connection.sendRequest(CORE_METHODS.CONNECT, params);
3178
+ this.#sessionId = result.sessionId;
3179
+ this.#serverCapabilities = result.capabilities;
3180
+ this.#connected = true;
3181
+ this.#connection._transitionTo("connected");
3182
+ this.#lastConnectOptions = options;
3183
+ return result;
3184
+ }
3185
+ /**
3186
+ * Disconnect from the local MAP system
3187
+ */
3188
+ async disconnect(reason) {
3189
+ if (!this.#connected) return;
3190
+ try {
3191
+ await this.#connection.sendRequest(
3192
+ CORE_METHODS.DISCONNECT,
3193
+ reason ? { reason } : void 0
3194
+ );
3195
+ } finally {
3196
+ await this.#connection.close();
3197
+ this.#connected = false;
3198
+ }
3199
+ }
3200
+ /**
3201
+ * Whether the gateway is connected to the local system
3202
+ */
3203
+ get isConnected() {
3204
+ return this.#connected && !this.#connection.isClosed;
3205
+ }
3206
+ /**
3207
+ * Current session ID
3208
+ */
3209
+ get sessionId() {
3210
+ return this.#sessionId;
3211
+ }
3212
+ /**
3213
+ * Server capabilities
3214
+ */
3215
+ get serverCapabilities() {
3216
+ return this.#serverCapabilities;
3217
+ }
3218
+ /**
3219
+ * List of connected remote systems
3220
+ */
3221
+ get connectedSystems() {
3222
+ return new Map(this.#connectedSystems);
3223
+ }
3224
+ /**
3225
+ * AbortSignal that triggers when the connection closes
3226
+ */
3227
+ get signal() {
3228
+ return this.#connection.signal;
3229
+ }
3230
+ /**
3231
+ * Promise that resolves when the connection closes
3232
+ */
3233
+ get closed() {
3234
+ return this.#connection.closed;
3235
+ }
3236
+ // ===========================================================================
3237
+ // Federation
3238
+ // ===========================================================================
3239
+ /**
3240
+ * Connect to a remote MAP system
3241
+ */
3242
+ async connectToSystem(systemId, endpoint, auth) {
3243
+ const params = {
3244
+ systemId,
3245
+ endpoint,
3246
+ auth
3247
+ };
3248
+ const result = await this.#connection.sendRequest(FEDERATION_METHODS.FEDERATION_CONNECT, params);
3249
+ if (result.connected && result.systemInfo) {
3250
+ this.#connectedSystems.set(systemId, {
3251
+ name: result.systemInfo.name,
3252
+ version: result.systemInfo.version
3253
+ });
3254
+ }
3255
+ return result;
3256
+ }
3257
+ /**
3258
+ * Route a message to a remote system.
3259
+ *
3260
+ * If routing config is provided, wraps the message in a federation envelope
3261
+ * with proper metadata for multi-hop routing. Otherwise, sends raw message
3262
+ * for backwards compatibility.
3263
+ *
3264
+ * During reconnection, messages are buffered if buffer is configured.
3265
+ */
3266
+ async routeToSystem(systemId, message) {
3267
+ let envelope;
3268
+ if (this.#options.routing) {
3269
+ envelope = createFederationEnvelope(
3270
+ message,
3271
+ this.#options.routing.systemId,
3272
+ systemId,
3273
+ {
3274
+ maxHops: this.#options.routing.maxHops,
3275
+ trackPath: this.#options.routing.trackPath
3276
+ }
3277
+ );
3278
+ }
3279
+ if (this.#isReconnecting && this.#outageBuffer && envelope) {
3280
+ const buffered = this.#outageBuffer.enqueue(systemId, envelope);
3281
+ if (!buffered) {
3282
+ this.#emitReconnectionEvent({
3283
+ type: "bufferOverflow",
3284
+ peerId: systemId,
3285
+ messagesBuffered: this.#outageBuffer.count(systemId)
3286
+ });
3287
+ }
3288
+ return { routed: false };
3289
+ }
3290
+ const params = { systemId };
3291
+ if (envelope) {
3292
+ params.envelope = envelope;
3293
+ } else {
3294
+ params.message = message;
3295
+ }
3296
+ const result = await this.#connection.sendRequest(FEDERATION_METHODS.FEDERATION_ROUTE, params);
3297
+ if (result.routed) {
3298
+ this.#lastSyncTimestamps.set(systemId, Date.now());
3299
+ }
3300
+ return result;
3301
+ }
3302
+ /**
3303
+ * Check if a remote system is connected
3304
+ */
3305
+ isSystemConnected(systemId) {
3306
+ return this.#connectedSystems.has(systemId);
3307
+ }
3308
+ // ===========================================================================
3309
+ // Reconnection
3310
+ // ===========================================================================
3311
+ /**
3312
+ * Current connection state
3313
+ */
3314
+ get state() {
3315
+ return this.#connection.state;
3316
+ }
3317
+ /**
3318
+ * Whether the connection is currently reconnecting
3319
+ */
3320
+ get isReconnecting() {
3321
+ return this.#isReconnecting;
3322
+ }
3323
+ /**
3324
+ * Get the outage buffer (for advanced use)
3325
+ */
3326
+ get outageBuffer() {
3327
+ return this.#outageBuffer;
3328
+ }
3329
+ /**
3330
+ * Get last sync timestamp for a peer
3331
+ */
3332
+ getLastSyncTimestamp(peerId) {
3333
+ return this.#lastSyncTimestamps.get(peerId);
3334
+ }
3335
+ /**
3336
+ * Register a handler for reconnection events.
3337
+ *
3338
+ * @param handler - Function called when reconnection events occur
3339
+ * @returns Unsubscribe function to remove the handler
3340
+ */
3341
+ onReconnection(handler) {
3342
+ this.#reconnectionHandlers.add(handler);
3343
+ return () => this.#reconnectionHandlers.delete(handler);
3344
+ }
3345
+ /**
3346
+ * Register a handler for connection state changes.
3347
+ *
3348
+ * @param handler - Function called when state changes
3349
+ * @returns Unsubscribe function to remove the handler
3350
+ */
3351
+ onStateChange(handler) {
3352
+ return this.#connection.onStateChange(handler);
3353
+ }
3354
+ // ===========================================================================
3355
+ // Internal
3356
+ // ===========================================================================
3357
+ /**
3358
+ * Emit a reconnection event to all registered handlers
3359
+ */
3360
+ #emitReconnectionEvent(event) {
3361
+ for (const handler of this.#reconnectionHandlers) {
3362
+ try {
3363
+ handler(event);
3364
+ } catch (error) {
3365
+ console.error("MAP: Gateway reconnection event handler error:", error);
3366
+ }
3367
+ }
3368
+ }
3369
+ /**
3370
+ * Handle disconnect when auto-reconnect is enabled
3371
+ */
3372
+ async #handleDisconnect() {
3373
+ this.#isReconnecting = true;
3374
+ this.#connected = false;
3375
+ this.#emitReconnectionEvent({ type: "disconnected" });
3376
+ try {
3377
+ await this.#attemptReconnect();
3378
+ } catch (error) {
3379
+ this.#isReconnecting = false;
3380
+ this.#emitReconnectionEvent({
3381
+ type: "reconnectFailed",
3382
+ error: error instanceof Error ? error : new Error(String(error))
3383
+ });
3384
+ }
3385
+ }
3386
+ /**
3387
+ * Attempt to reconnect with retry logic
3388
+ */
3389
+ async #attemptReconnect() {
3390
+ const options = this.#options.reconnection;
3391
+ const createStream = this.#options.createStream;
3392
+ const retryPolicy = {
3393
+ maxRetries: options.maxRetries ?? DEFAULT_RETRY_POLICY.maxRetries,
3394
+ baseDelayMs: options.baseDelayMs ?? DEFAULT_RETRY_POLICY.baseDelayMs,
3395
+ maxDelayMs: options.maxDelayMs ?? DEFAULT_RETRY_POLICY.maxDelayMs,
3396
+ jitter: options.jitter ?? DEFAULT_RETRY_POLICY.jitter
3397
+ };
3398
+ await withRetry(
3399
+ async () => {
3400
+ const newStream = await createStream();
3401
+ await this.#connection.reconnect(newStream);
3402
+ const connectResult = await this.connect(this.#lastConnectOptions);
3403
+ this.#sessionId = connectResult.sessionId;
3404
+ this.#serverCapabilities = connectResult.capabilities;
3405
+ },
3406
+ retryPolicy,
3407
+ {
3408
+ onRetry: (state) => {
3409
+ this.#emitReconnectionEvent({
3410
+ type: "reconnecting",
3411
+ attempt: state.attempt,
3412
+ delay: state.nextDelayMs,
3413
+ error: state.lastError
3414
+ });
3415
+ }
3416
+ }
3417
+ );
3418
+ this.#isReconnecting = false;
3419
+ this.#emitReconnectionEvent({ type: "reconnected" });
3420
+ await this.#drainBufferedMessages();
3421
+ await this.#replayFromPeers();
3422
+ }
3423
+ /**
3424
+ * Drain buffered messages after reconnection
3425
+ */
3426
+ async #drainBufferedMessages() {
3427
+ if (!this.#outageBuffer) return;
3428
+ const peers = this.#outageBuffer.peers();
3429
+ for (const peerId of peers) {
3430
+ const messages = this.#outageBuffer.drain(peerId);
3431
+ if (messages.length === 0) continue;
3432
+ for (const envelope of messages) {
3433
+ try {
3434
+ const params = {
3435
+ systemId: peerId,
3436
+ envelope
3437
+ };
3438
+ await this.#connection.sendRequest(FEDERATION_METHODS.FEDERATION_ROUTE, params);
3439
+ } catch (error) {
3440
+ console.warn("MAP: Failed to send buffered message to", peerId, error);
3441
+ }
3442
+ }
3443
+ this.#emitReconnectionEvent({
3444
+ type: "bufferDrained",
3445
+ peerId,
3446
+ messagesDrained: messages.length
3447
+ });
3448
+ }
3449
+ }
3450
+ /**
3451
+ * Replay missed events from peers after reconnection
3452
+ */
3453
+ async #replayFromPeers() {
3454
+ const replayOptions = this.#options.replay;
3455
+ if (!replayOptions?.enabled) return;
3456
+ const peersToReplay = Array.from(this.#lastSyncTimestamps.entries());
3457
+ if (peersToReplay.length === 0) return;
3458
+ for (const [peerId, lastSync] of peersToReplay) {
3459
+ try {
3460
+ await this.#replayFromPeer(peerId, lastSync);
3461
+ } catch (error) {
3462
+ console.warn("MAP: Failed to replay events from peer", peerId, error);
3463
+ }
3464
+ }
3465
+ }
3466
+ /**
3467
+ * Replay missed events from a single peer
3468
+ */
3469
+ async #replayFromPeer(peerId, lastSyncTimestamp) {
3470
+ const replayOptions = this.#options.replay;
3471
+ const maxAge = replayOptions.maxAgeMs ?? 60 * 60 * 1e3;
3472
+ const cutoff = Date.now() - maxAge;
3473
+ if (lastSyncTimestamp < cutoff) {
3474
+ return;
3475
+ }
3476
+ this.#emitReconnectionEvent({ type: "replayStarted", peerId });
3477
+ let totalReplayed = 0;
3478
+ const maxEvents = replayOptions.maxEvents ?? 1e3;
3479
+ let afterEventId;
3480
+ let hasMore = true;
3481
+ while (hasMore && totalReplayed < maxEvents) {
3482
+ const params = {
3483
+ limit: Math.min(100, maxEvents - totalReplayed)
3484
+ };
3485
+ if (afterEventId) {
3486
+ params.afterEventId = afterEventId;
3487
+ } else {
3488
+ params.fromTimestamp = lastSyncTimestamp;
3489
+ }
3490
+ if (replayOptions.eventTypes) {
3491
+ params.filter = { eventTypes: replayOptions.eventTypes };
3492
+ }
3493
+ const result = await this.#connection.sendRequest(CORE_METHODS.REPLAY, params);
3494
+ totalReplayed += result.events.length;
3495
+ hasMore = result.hasMore;
3496
+ afterEventId = result.events.at(-1)?.eventId;
3497
+ if (result.events.length === 0) {
3498
+ break;
3499
+ }
3500
+ const lastEvent = result.events.at(-1);
3501
+ if (lastEvent) {
3502
+ this.#lastSyncTimestamps.set(peerId, lastEvent.timestamp);
3503
+ }
3504
+ }
3505
+ this.#emitReconnectionEvent({
3506
+ type: "replayCompleted",
3507
+ peerId,
3508
+ eventsReplayed: totalReplayed
3509
+ });
3510
+ }
3511
+ };
3512
+ var JsonRpcVersionSchema = zod.z.literal("2.0");
3513
+ var RequestIdSchema = zod.z.union([zod.z.string(), zod.z.number().int()]);
3514
+ var ProtocolVersionSchema = zod.z.literal(1);
3515
+ var TimestampSchema = zod.z.number().int();
3516
+ var MetaSchema = zod.z.record(zod.z.unknown()).optional();
3517
+ var ParticipantIdSchema = zod.z.string();
3518
+ var AgentIdSchema = zod.z.string();
3519
+ var ScopeIdSchema = zod.z.string();
3520
+ var SessionIdSchema = zod.z.string();
3521
+ var MessageIdSchema = zod.z.string();
3522
+ var SubscriptionIdSchema = zod.z.string();
3523
+ var CorrelationIdSchema = zod.z.string();
3524
+ var ParticipantTypeSchema = zod.z.enum(["agent", "client", "system", "gateway"]);
3525
+ var TransportTypeSchema = zod.z.enum(["websocket", "stdio", "inprocess", "http-sse"]);
3526
+ var ErrorCategorySchema = zod.z.enum([
3527
+ "protocol",
3528
+ "auth",
3529
+ "routing",
3530
+ "agent",
3531
+ "resource",
3532
+ "federation",
3533
+ "internal"
3534
+ ]);
3535
+ var AgentVisibilitySchema = zod.z.enum(["public", "parent-only", "scope", "system"]);
3536
+ var AgentStateSchema = zod.z.union([
3537
+ zod.z.enum(["registered", "idle", "busy", "waiting", "stopping", "stopped", "error"]),
3538
+ zod.z.string().regex(/^x-/)
3539
+ ]);
3540
+ var MessagePrioritySchema = zod.z.enum(["low", "normal", "high", "urgent"]);
3541
+ var DeliverySemanticsSchema = zod.z.enum(["at-most-once", "at-least-once", "exactly-once"]);
3542
+ var MessageRelationshipSchema = zod.z.enum([
3543
+ "peer",
3544
+ "parent-to-child",
3545
+ "child-to-parent",
3546
+ "supervisor-to-supervised",
3547
+ "broadcast"
3548
+ ]);
3549
+ var EventTypeSchema = zod.z.enum([
3550
+ "agent.registered",
3551
+ "agent.unregistered",
3552
+ "agent.state-changed",
3553
+ "agent.spawned",
3554
+ "scope.created",
3555
+ "scope.deleted",
3556
+ "scope.joined",
3557
+ "scope.left",
3558
+ "message.sent",
3559
+ "message.delivered",
3560
+ "session.started",
3561
+ "session.ended",
3562
+ "system.error",
3563
+ "system.shutdown"
3564
+ ]);
3565
+ var ScopeJoinPolicySchema = zod.z.enum(["open", "approval", "invite"]);
3566
+ var ScopeVisibilitySchema = zod.z.enum(["public", "private", "unlisted"]);
3567
+ var MessageVisibilitySchema = zod.z.enum(["members", "public"]);
3568
+ var ScopeSendPolicySchema = zod.z.enum(["anyone", "members"]);
3569
+ var ParticipantCapabilitiesSchema = zod.z.object({
3570
+ observation: zod.z.object({
3571
+ canObserve: zod.z.boolean().optional(),
3572
+ canQuery: zod.z.boolean().optional()
3573
+ }).strict().optional(),
3574
+ messaging: zod.z.object({
3575
+ canSend: zod.z.boolean().optional(),
3576
+ canReceive: zod.z.boolean().optional(),
3577
+ canBroadcast: zod.z.boolean().optional()
3578
+ }).strict().optional(),
3579
+ lifecycle: zod.z.object({
3580
+ canSpawn: zod.z.boolean().optional(),
3581
+ canRegister: zod.z.boolean().optional(),
3582
+ canUnregister: zod.z.boolean().optional(),
3583
+ canSteer: zod.z.boolean().optional(),
3584
+ canStop: zod.z.boolean().optional()
3585
+ }).strict().optional(),
3586
+ scopes: zod.z.object({
3587
+ canCreateScopes: zod.z.boolean().optional(),
3588
+ canManageScopes: zod.z.boolean().optional()
3589
+ }).strict().optional(),
3590
+ _meta: MetaSchema
3591
+ }).strict();
3592
+ var DirectAddressSchema = zod.z.object({ agent: AgentIdSchema }).strict();
3593
+ var MultiAddressSchema = zod.z.object({ agents: zod.z.array(AgentIdSchema).min(1) }).strict();
3594
+ var ScopeAddressSchema = zod.z.object({ scope: ScopeIdSchema }).strict();
3595
+ var RoleAddressSchema = zod.z.object({
3596
+ role: zod.z.string(),
3597
+ scope: ScopeIdSchema.optional()
3598
+ }).strict();
3599
+ var HierarchicalAddressSchema = zod.z.object({
3600
+ parent: zod.z.literal(true).optional(),
3601
+ children: zod.z.literal(true).optional(),
3602
+ siblings: zod.z.literal(true).optional(),
3603
+ ancestors: zod.z.literal(true).optional(),
3604
+ descendants: zod.z.literal(true).optional()
3605
+ }).strict();
3606
+ var BroadcastAddressSchema = zod.z.object({ broadcast: zod.z.literal(true) }).strict();
3607
+ var SystemAddressSchema = zod.z.object({ system: zod.z.literal(true) }).strict();
3608
+ var ParticipantAddressSchema = zod.z.object({ participant: ParticipantIdSchema }).strict();
3609
+ var FederatedAddressSchema = zod.z.object({
3610
+ system: zod.z.string(),
3611
+ address: zod.z.lazy(() => AddressSchema)
3612
+ }).strict();
3613
+ var AddressSchema = zod.z.union([
3614
+ DirectAddressSchema,
3615
+ MultiAddressSchema,
3616
+ ScopeAddressSchema,
3617
+ RoleAddressSchema,
3618
+ HierarchicalAddressSchema,
3619
+ BroadcastAddressSchema,
3620
+ SystemAddressSchema,
3621
+ ParticipantAddressSchema,
3622
+ FederatedAddressSchema
3623
+ ]);
3624
+ var AgentRelationshipSchema = zod.z.object({
3625
+ type: zod.z.enum(["peer", "supervisor", "supervised", "collaborator"]),
3626
+ agentId: AgentIdSchema,
3627
+ metadata: zod.z.record(zod.z.unknown()).optional(),
3628
+ _meta: MetaSchema
3629
+ }).strict();
3630
+ var AgentLifecycleSchema = zod.z.object({
3631
+ createdAt: TimestampSchema.optional(),
3632
+ startedAt: TimestampSchema.optional(),
3633
+ stoppedAt: TimestampSchema.optional(),
3634
+ lastActiveAt: TimestampSchema.optional(),
3635
+ exitCode: zod.z.number().int().optional(),
3636
+ exitReason: zod.z.string().optional(),
3637
+ _meta: MetaSchema
3638
+ }).strict();
3639
+ var AgentSchema = zod.z.object({
3640
+ id: AgentIdSchema,
3641
+ name: zod.z.string().optional(),
3642
+ description: zod.z.string().optional(),
3643
+ parent: AgentIdSchema.optional(),
3644
+ relationships: zod.z.array(AgentRelationshipSchema).optional(),
3645
+ state: AgentStateSchema,
3646
+ role: zod.z.string().optional(),
3647
+ scopes: zod.z.array(ScopeIdSchema).optional(),
3648
+ visibility: AgentVisibilitySchema.optional(),
3649
+ lifecycle: AgentLifecycleSchema.optional(),
3650
+ capabilities: ParticipantCapabilitiesSchema.optional(),
3651
+ metadata: zod.z.record(zod.z.unknown()).optional(),
3652
+ _meta: MetaSchema
3653
+ }).strict();
3654
+ var ScopeSchema = zod.z.object({
3655
+ id: ScopeIdSchema,
3656
+ name: zod.z.string().optional(),
3657
+ parent: ScopeIdSchema.optional(),
3658
+ children: zod.z.array(ScopeIdSchema).optional(),
3659
+ joinPolicy: ScopeJoinPolicySchema.optional(),
3660
+ visibility: ScopeVisibilitySchema.optional(),
3661
+ messageVisibility: MessageVisibilitySchema.optional(),
3662
+ sendPolicy: ScopeSendPolicySchema.optional(),
3663
+ metadata: zod.z.record(zod.z.unknown()).optional(),
3664
+ _meta: MetaSchema
3665
+ }).strict();
3666
+ var MessageMetaSchema = zod.z.object({
3667
+ correlationId: CorrelationIdSchema.optional(),
3668
+ causationId: MessageIdSchema.optional(),
3669
+ traceId: zod.z.string().optional(),
3670
+ spanId: zod.z.string().optional(),
3671
+ priority: MessagePrioritySchema.optional(),
3672
+ delivery: DeliverySemanticsSchema.optional(),
3673
+ relationship: MessageRelationshipSchema.optional(),
3674
+ expiresAt: TimestampSchema.optional(),
3675
+ isResult: zod.z.boolean().optional(),
3676
+ _meta: MetaSchema
3677
+ }).strict();
3678
+ var MessageSchema = zod.z.object({
3679
+ id: MessageIdSchema,
3680
+ from: ParticipantIdSchema,
3681
+ to: AddressSchema,
3682
+ timestamp: TimestampSchema,
3683
+ payload: zod.z.unknown().optional(),
3684
+ meta: MessageMetaSchema.optional(),
3685
+ _meta: MetaSchema
3686
+ }).strict();
3687
+ var EventSchema = zod.z.object({
3688
+ type: EventTypeSchema,
3689
+ timestamp: TimestampSchema,
3690
+ data: zod.z.record(zod.z.unknown()).optional(),
3691
+ _meta: MetaSchema
3692
+ }).strict();
3693
+ var SubscriptionFilterSchema = zod.z.object({
3694
+ eventTypes: zod.z.array(EventTypeSchema).optional(),
3695
+ scopes: zod.z.array(ScopeIdSchema).optional(),
3696
+ agents: zod.z.array(AgentIdSchema).optional(),
3697
+ includeChildren: zod.z.boolean().optional(),
3698
+ _meta: MetaSchema
3699
+ }).strict();
3700
+ var MAPErrorDataSchema = zod.z.object({
3701
+ category: ErrorCategorySchema.optional(),
3702
+ retryable: zod.z.boolean().optional(),
3703
+ retryAfterMs: zod.z.number().int().optional(),
3704
+ details: zod.z.record(zod.z.unknown()).optional(),
3705
+ _meta: MetaSchema
3706
+ }).passthrough();
3707
+ var MAPErrorSchema = zod.z.object({
3708
+ code: zod.z.number().int(),
3709
+ message: zod.z.string(),
3710
+ data: MAPErrorDataSchema.optional()
3711
+ }).strict();
3712
+ var MAPRequestSchema = zod.z.object({
3713
+ jsonrpc: JsonRpcVersionSchema,
3714
+ id: RequestIdSchema,
3715
+ method: zod.z.string(),
3716
+ params: zod.z.record(zod.z.unknown()).optional()
3717
+ }).strict();
3718
+ var MAPResponseSuccessSchema = zod.z.object({
3719
+ jsonrpc: JsonRpcVersionSchema,
3720
+ id: RequestIdSchema,
3721
+ result: zod.z.unknown()
3722
+ }).strict();
3723
+ var MAPResponseErrorSchema = zod.z.object({
3724
+ jsonrpc: JsonRpcVersionSchema,
3725
+ id: RequestIdSchema,
3726
+ error: MAPErrorSchema
3727
+ }).strict();
3728
+ var MAPResponseSchema = zod.z.union([MAPResponseSuccessSchema, MAPResponseErrorSchema]);
3729
+ var MAPNotificationSchema = zod.z.object({
3730
+ jsonrpc: JsonRpcVersionSchema,
3731
+ method: zod.z.string(),
3732
+ params: zod.z.record(zod.z.unknown()).optional()
3733
+ }).strict();
3734
+
3735
+ // src/protocol/index.ts
3736
+ var METHOD_REGISTRY = {
3737
+ // Core methods
3738
+ "connect": {
3739
+ method: "map/connect",
3740
+ category: "core",
3741
+ capabilities: [],
3742
+ description: "Establish connection to MAP system"
3743
+ },
3744
+ "disconnect": {
3745
+ method: "map/disconnect",
3746
+ category: "core",
3747
+ capabilities: [],
3748
+ description: "Disconnect from MAP system"
3749
+ },
3750
+ "send": {
3751
+ method: "map/send",
3752
+ category: "core",
3753
+ capabilities: ["messaging.canSend"],
3754
+ description: "Send a message to an address"
3755
+ },
3756
+ "subscribe": {
3757
+ method: "map/subscribe",
3758
+ category: "core",
3759
+ capabilities: ["observation.canObserve"],
3760
+ description: "Subscribe to event stream"
3761
+ },
3762
+ "unsubscribe": {
3763
+ method: "map/unsubscribe",
3764
+ category: "core",
3765
+ capabilities: ["observation.canObserve"],
3766
+ description: "Unsubscribe from event stream"
3767
+ },
3768
+ "replay": {
3769
+ method: "map/replay",
3770
+ category: "core",
3771
+ capabilities: ["observation.canObserve"],
3772
+ description: "Replay historical events with filtering and pagination"
3773
+ },
3774
+ // Observation methods
3775
+ "agents/list": {
3776
+ method: "map/agents/list",
3777
+ category: "observation",
3778
+ capabilities: ["observation.canQuery"],
3779
+ description: "List agents with optional filters"
3780
+ },
3781
+ "agents/get": {
3782
+ method: "map/agents/get",
3783
+ category: "observation",
3784
+ capabilities: ["observation.canQuery"],
3785
+ description: "Get agent by ID with optional hierarchy"
3786
+ },
3787
+ "scopes/list": {
3788
+ method: "map/scopes/list",
3789
+ category: "observation",
3790
+ capabilities: ["observation.canQuery"],
3791
+ description: "List all scopes"
3792
+ },
3793
+ "scopes/get": {
3794
+ method: "map/scopes/get",
3795
+ category: "observation",
3796
+ capabilities: ["observation.canQuery"],
3797
+ description: "Get scope by ID"
3798
+ },
3799
+ "scopes/members": {
3800
+ method: "map/scopes/members",
3801
+ category: "observation",
3802
+ capabilities: ["observation.canQuery"],
3803
+ description: "List scope members"
3804
+ },
3805
+ "structure/graph": {
3806
+ method: "map/structure/graph",
3807
+ category: "observation",
3808
+ capabilities: ["observation.canQuery"],
3809
+ description: "Get agent hierarchy graph"
3810
+ },
3811
+ // Lifecycle methods
3812
+ "agents/register": {
3813
+ method: "map/agents/register",
3814
+ category: "lifecycle",
3815
+ capabilities: ["lifecycle.canRegister"],
3816
+ description: "Register a new agent"
3817
+ },
3818
+ "agents/unregister": {
3819
+ method: "map/agents/unregister",
3820
+ category: "lifecycle",
3821
+ capabilities: ["lifecycle.canUnregister"],
3822
+ description: "Unregister an agent"
3823
+ },
3824
+ "agents/spawn": {
3825
+ method: "map/agents/spawn",
3826
+ category: "lifecycle",
3827
+ capabilities: ["lifecycle.canSpawn"],
3828
+ description: "Spawn a child agent"
3829
+ },
3830
+ // State methods
3831
+ "agents/update": {
3832
+ method: "map/agents/update",
3833
+ category: "state",
3834
+ capabilities: ["lifecycle.canRegister"],
3835
+ description: "Update agent state or metadata"
3836
+ },
3837
+ "agents/suspend": {
3838
+ method: "map/agents/suspend",
3839
+ category: "state",
3840
+ capabilities: ["lifecycle.canStop"],
3841
+ description: "Suspend an agent"
3842
+ },
3843
+ "agents/resume": {
3844
+ method: "map/agents/resume",
3845
+ category: "state",
3846
+ capabilities: ["lifecycle.canStop"],
3847
+ description: "Resume a suspended agent"
3848
+ },
3849
+ "agents/stop": {
3850
+ method: "map/agents/stop",
3851
+ category: "state",
3852
+ capabilities: ["lifecycle.canStop"],
3853
+ description: "Stop an agent"
3854
+ },
3855
+ // Steering methods
3856
+ "inject": {
3857
+ method: "map/inject",
3858
+ category: "steering",
3859
+ capabilities: ["lifecycle.canSteer"],
3860
+ description: "Inject context into an agent"
3861
+ },
3862
+ // Scope methods
3863
+ "scopes/create": {
3864
+ method: "map/scopes/create",
3865
+ category: "scope",
3866
+ capabilities: ["scopes.canCreateScopes"],
3867
+ description: "Create a new scope"
3868
+ },
3869
+ "scopes/delete": {
3870
+ method: "map/scopes/delete",
3871
+ category: "scope",
3872
+ capabilities: ["scopes.canManageScopes"],
3873
+ description: "Delete a scope"
3874
+ },
3875
+ "scopes/join": {
3876
+ method: "map/scopes/join",
3877
+ category: "scope",
3878
+ capabilities: [],
3879
+ description: "Join a scope"
3880
+ },
3881
+ "scopes/leave": {
3882
+ method: "map/scopes/leave",
3883
+ category: "scope",
3884
+ capabilities: [],
3885
+ description: "Leave a scope"
3886
+ },
3887
+ // Session methods
3888
+ "session/list": {
3889
+ method: "map/session/list",
3890
+ category: "session",
3891
+ capabilities: [],
3892
+ description: "List sessions"
3893
+ },
3894
+ "session/load": {
3895
+ method: "map/session/load",
3896
+ category: "session",
3897
+ capabilities: [],
3898
+ description: "Load a session"
3899
+ },
3900
+ "session/close": {
3901
+ method: "map/session/close",
3902
+ category: "session",
3903
+ capabilities: [],
3904
+ description: "Close a session"
3905
+ },
3906
+ // Auth methods
3907
+ "auth/refresh": {
3908
+ method: "map/auth/refresh",
3909
+ category: "auth",
3910
+ capabilities: [],
3911
+ description: "Refresh authentication token"
3912
+ },
3913
+ // Federation methods
3914
+ "federation/connect": {
3915
+ method: "map/federation/connect",
3916
+ category: "federation",
3917
+ capabilities: ["federation.canFederate"],
3918
+ description: "Connect to federated system"
3919
+ },
3920
+ "federation/route": {
3921
+ method: "map/federation/route",
3922
+ category: "federation",
3923
+ capabilities: ["federation.canFederate"],
3924
+ description: "Route message to federated system"
3925
+ },
3926
+ // Notification methods (client → server)
3927
+ "subscription/ack": {
3928
+ method: "map/subscribe.ack",
3929
+ category: "notification",
3930
+ capabilities: [],
3931
+ description: "Acknowledge received events for backpressure flow control"
3932
+ }
3933
+ };
3934
+ function getMethodsByCategory(category) {
3935
+ return Object.values(METHOD_REGISTRY).filter((m) => m.category === category);
3936
+ }
3937
+ function getRequiredCapabilities(methodName) {
3938
+ const info = METHOD_REGISTRY[methodName];
3939
+ if (info) return info.capabilities;
3940
+ const byWire = Object.values(METHOD_REGISTRY).find((m) => m.method === methodName);
3941
+ return byWire?.capabilities ?? [];
3942
+ }
3943
+ function hasRequiredCapabilities(methodName, capabilities) {
3944
+ const required = getRequiredCapabilities(methodName);
3945
+ if (required.length === 0) return true;
3946
+ for (const path of required) {
3947
+ const [category, capability] = path.split(".");
3948
+ const categoryCapabilities = capabilities[category];
3949
+ if (!categoryCapabilities?.[capability]) {
3950
+ return false;
3951
+ }
3952
+ }
3953
+ return true;
3954
+ }
3955
+ function getMethodInfo(wireMethod) {
3956
+ return Object.values(METHOD_REGISTRY).find((m) => m.method === wireMethod);
3957
+ }
3958
+ function buildConnectResponse(params) {
3959
+ return {
3960
+ protocolVersion: params.protocolVersion,
3961
+ sessionId: params.sessionId,
3962
+ participantId: params.participantId,
3963
+ capabilities: params.capabilities,
3964
+ systemInfo: params.systemInfo,
3965
+ reconnected: params.reconnected,
3966
+ reclaimedAgents: params.reclaimedAgents,
3967
+ ownedAgents: params.ownedAgents
3968
+ };
3969
+ }
3970
+ function buildDisconnectResponse(session) {
3971
+ return { session };
3972
+ }
3973
+ function buildSendResponse(messageId, delivered) {
3974
+ return { messageId, delivered };
3975
+ }
3976
+ function buildAgentsRegisterResponse(agent) {
3977
+ return { agent };
3978
+ }
3979
+ function buildAgentsUnregisterResponse(agent) {
3980
+ return { agent };
3981
+ }
3982
+ function buildAgentsListResponse(agents) {
3983
+ return { agents };
3984
+ }
3985
+ function buildAgentsGetResponse(agent, children, descendants) {
3986
+ const result = { agent };
3987
+ if (children) result.children = children;
3988
+ if (descendants) result.descendants = descendants;
3989
+ return result;
3990
+ }
3991
+ function buildAgentsUpdateResponse(agent) {
3992
+ return { agent };
3993
+ }
3994
+ function buildAgentsSpawnResponse(agent) {
3995
+ return { agent };
3996
+ }
3997
+ function buildScopesCreateResponse(scope) {
3998
+ return { scope };
3999
+ }
4000
+ function buildScopesListResponse(scopes) {
4001
+ return { scopes };
4002
+ }
4003
+ function buildScopesJoinResponse(scope, agent) {
4004
+ return { scope, agent };
4005
+ }
4006
+ function buildScopesLeaveResponse(scope, agent) {
4007
+ return { scope, agent };
4008
+ }
4009
+ function buildSubscribeResponse(subscriptionId) {
4010
+ return { subscriptionId };
4011
+ }
4012
+ function buildUnsubscribeResponse(subscriptionId, closedAt = Date.now()) {
4013
+ return {
4014
+ subscription: {
4015
+ id: subscriptionId,
4016
+ closedAt
4017
+ }
4018
+ };
4019
+ }
4020
+
4021
+ // src/permissions/index.ts
4022
+ function isAgentExposed(exposure, agentId) {
4023
+ if (!exposure?.agents) return true;
4024
+ const {
4025
+ publicByDefault = true,
4026
+ publicAgents = [],
4027
+ hiddenAgents = []
4028
+ } = exposure.agents;
4029
+ if (matchesPatterns(agentId, hiddenAgents)) return false;
4030
+ if (matchesPatterns(agentId, publicAgents)) return true;
4031
+ return publicByDefault;
4032
+ }
4033
+ function isEventTypeExposed(exposure, eventType) {
4034
+ if (!exposure?.events) return true;
4035
+ const { exposedTypes, hiddenTypes = [] } = exposure.events;
4036
+ if (hiddenTypes.includes(eventType)) return false;
4037
+ if (exposedTypes && !exposedTypes.includes(eventType)) return false;
4038
+ return true;
4039
+ }
4040
+ function isScopeExposed(exposure, scopeId) {
4041
+ if (!exposure?.scopes) return true;
4042
+ const {
4043
+ publicByDefault = true,
4044
+ publicScopes = [],
4045
+ hiddenScopes = []
4046
+ } = exposure.scopes;
4047
+ if (matchesPatterns(scopeId, hiddenScopes)) return false;
4048
+ if (matchesPatterns(scopeId, publicScopes)) return true;
4049
+ return publicByDefault;
4050
+ }
4051
+ function hasCapability(capabilities, path) {
4052
+ const [category, cap] = path.split(".");
4053
+ const categoryCapabilities = capabilities[category];
4054
+ return categoryCapabilities?.[cap] ?? false;
4055
+ }
4056
+ function canPerformMethod(method, capabilities) {
4057
+ return hasRequiredCapabilities(method, capabilities);
4058
+ }
4059
+ function canSeeScope(scope, participant, memberAgentIds = []) {
4060
+ const visibility = scope.visibility ?? "public";
4061
+ switch (visibility) {
4062
+ case "public":
4063
+ return true;
4064
+ case "members":
4065
+ return memberAgentIds.length > 0;
4066
+ case "system":
4067
+ return participant.type === "system";
4068
+ default:
4069
+ return false;
4070
+ }
4071
+ }
4072
+ function canSendToScope(scope, participant, memberAgentIds = []) {
4073
+ if (participant.type === "system") return true;
4074
+ const sendPolicy = scope.sendPolicy ?? "members";
4075
+ switch (sendPolicy) {
4076
+ case "any":
4077
+ return true;
4078
+ case "members":
4079
+ return memberAgentIds.length > 0;
4080
+ default:
4081
+ return false;
4082
+ }
4083
+ }
4084
+ function canJoinScope(scope, participantType, agentRole) {
4085
+ const joinPolicy = scope.joinPolicy ?? "open";
4086
+ switch (joinPolicy) {
4087
+ case "open":
4088
+ return true;
4089
+ case "invite":
4090
+ return false;
4091
+ case "role":
4092
+ if (!agentRole || !scope.autoJoinRoles) return false;
4093
+ return scope.autoJoinRoles.includes(agentRole);
4094
+ case "system":
4095
+ return participantType === "system";
4096
+ default:
4097
+ return false;
4098
+ }
4099
+ }
4100
+ function canSeeAgent(agent, participant, ownedAgentIds = []) {
4101
+ const visibility = agent.visibility ?? "public";
4102
+ switch (visibility) {
4103
+ case "public":
4104
+ return true;
4105
+ case "parent-only":
4106
+ if (ownedAgentIds.includes(agent.id)) return true;
4107
+ return agent.parent ? ownedAgentIds.includes(agent.parent) : false;
4108
+ case "scope":
4109
+ return true;
4110
+ case "system":
4111
+ return participant.type === "system";
4112
+ default:
4113
+ return false;
4114
+ }
4115
+ }
4116
+ function canMessageAgent(agent, participant, ownedAgentIds = []) {
4117
+ if (!canSeeAgent(agent, participant, ownedAgentIds)) {
4118
+ return false;
4119
+ }
4120
+ return true;
4121
+ }
4122
+ function canControlAgent(agent, participant, ownedAgentIds = []) {
4123
+ if (participant.type === "system") return true;
4124
+ if (ownedAgentIds.includes(agent.id)) return true;
4125
+ if (agent.parent && ownedAgentIds.includes(agent.parent)) return true;
4126
+ return false;
4127
+ }
4128
+ function canPerformAction(context, action) {
4129
+ if (action.target?.agentId) {
4130
+ if (!isAgentExposed(context.system.exposure, action.target.agentId)) {
4131
+ return {
4132
+ allowed: false,
4133
+ reason: "Agent not exposed by system configuration",
4134
+ layer: 1
4135
+ };
4136
+ }
4137
+ }
4138
+ if (action.target?.scopeId) {
4139
+ if (!isScopeExposed(context.system.exposure, action.target.scopeId)) {
4140
+ return {
4141
+ allowed: false,
4142
+ reason: "Scope not exposed by system configuration",
4143
+ layer: 1
4144
+ };
4145
+ }
4146
+ }
4147
+ if (action.target?.eventTypes) {
4148
+ for (const eventType of action.target.eventTypes) {
4149
+ if (!isEventTypeExposed(context.system.exposure, eventType)) {
4150
+ return {
4151
+ allowed: false,
4152
+ reason: `Event type '${eventType}' not exposed by system configuration`,
4153
+ layer: 1
4154
+ };
4155
+ }
4156
+ }
4157
+ }
4158
+ const requiredCaps = getRequiredCapabilities(action.method);
4159
+ for (const cap of requiredCaps) {
4160
+ if (!hasCapability(context.participant.capabilities, cap)) {
4161
+ return {
4162
+ allowed: false,
4163
+ reason: `Missing required capability: ${cap}`,
4164
+ layer: 2
4165
+ };
4166
+ }
4167
+ }
4168
+ return { allowed: true };
4169
+ }
4170
+ function filterVisibleAgents(agents, context) {
4171
+ const ownedAgentIds = context.ownedAgentIds ?? [];
4172
+ return agents.filter((agent) => {
4173
+ if (!isAgentExposed(context.system.exposure, agent.id)) {
4174
+ return false;
4175
+ }
4176
+ if (!canSeeAgent(agent, context.participant, ownedAgentIds)) {
4177
+ return false;
4178
+ }
4179
+ return true;
4180
+ });
4181
+ }
4182
+ function filterVisibleScopes(scopes, context) {
4183
+ const scopeMembership = context.scopeMembership ?? /* @__PURE__ */ new Map();
4184
+ return scopes.filter((scope) => {
4185
+ if (!isScopeExposed(context.system.exposure, scope.id)) {
4186
+ return false;
4187
+ }
4188
+ const memberAgentIds = scopeMembership.get(scope.id) ?? [];
4189
+ if (!canSeeScope(scope, context.participant, memberAgentIds)) {
4190
+ return false;
4191
+ }
4192
+ return true;
4193
+ });
4194
+ }
4195
+ function filterVisibleEvents(events, context) {
4196
+ return events.filter((event) => {
4197
+ if (!isEventTypeExposed(context.system.exposure, event.type)) {
4198
+ return false;
4199
+ }
4200
+ return true;
4201
+ });
4202
+ }
4203
+ function matchesPatterns(value, patterns) {
4204
+ return patterns.some((pattern) => matchGlob(value, pattern));
4205
+ }
4206
+ function matchGlob(value, pattern) {
4207
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
4208
+ const regex = new RegExp(`^${escaped}$`);
4209
+ return regex.test(value);
4210
+ }
4211
+ function deepClone(obj) {
4212
+ return JSON.parse(JSON.stringify(obj));
4213
+ }
4214
+ function deepMergePermissions(base, override) {
4215
+ const result = { ...base };
4216
+ if (override.canSee) {
4217
+ result.canSee = { ...base.canSee, ...override.canSee };
4218
+ }
4219
+ if (override.canMessage) {
4220
+ result.canMessage = { ...base.canMessage, ...override.canMessage };
4221
+ }
4222
+ if (override.acceptsFrom) {
4223
+ result.acceptsFrom = { ...base.acceptsFrom, ...override.acceptsFrom };
4224
+ }
4225
+ return result;
4226
+ }
4227
+ function mapVisibilityToRule(visibility) {
4228
+ switch (visibility) {
4229
+ case "public":
4230
+ return "all";
4231
+ case "parent-only":
4232
+ return "hierarchy";
4233
+ case "scope":
4234
+ return "scoped";
4235
+ case "system":
4236
+ return "direct";
4237
+ default:
4238
+ return "all";
4239
+ }
4240
+ }
4241
+ var DEFAULT_AGENT_PERMISSION_CONFIG = {
4242
+ defaultPermissions: {
4243
+ canSee: {
4244
+ agents: "all",
4245
+ scopes: "all",
4246
+ structure: "full"
4247
+ },
4248
+ canMessage: {
4249
+ agents: "all",
4250
+ scopes: "all"
4251
+ },
4252
+ acceptsFrom: {
4253
+ agents: "all",
4254
+ clients: "all",
4255
+ systems: "all"
4256
+ }
4257
+ },
4258
+ rolePermissions: {}
4259
+ };
4260
+ function resolveAgentPermissions(agent, config = DEFAULT_AGENT_PERMISSION_CONFIG) {
4261
+ let permissions = deepClone(config.defaultPermissions);
4262
+ if (agent.role && config.rolePermissions[agent.role]) {
4263
+ permissions = deepMergePermissions(permissions, config.rolePermissions[agent.role]);
4264
+ }
4265
+ if (agent.permissionOverrides) {
4266
+ permissions = deepMergePermissions(permissions, agent.permissionOverrides);
4267
+ }
4268
+ if (agent.visibility && !agent.permissionOverrides?.canSee?.agents) {
4269
+ permissions.canSee = permissions.canSee ?? {};
4270
+ permissions.canSee.agents = mapVisibilityToRule(agent.visibility);
4271
+ }
4272
+ return permissions;
4273
+ }
4274
+ function checkAgentAcceptance(rule, context) {
4275
+ if (!rule || rule === "all") return true;
4276
+ if (rule === "hierarchy") {
4277
+ return context.isParent === true || context.isChild === true || context.isAncestor === true || context.isDescendant === true;
4278
+ }
4279
+ if (rule === "scoped") {
4280
+ return (context.sharedScopes?.length ?? 0) > 0;
4281
+ }
4282
+ if (typeof rule === "object" && "include" in rule) {
4283
+ return context.senderAgentId !== void 0 && rule.include.includes(context.senderAgentId);
4284
+ }
4285
+ return false;
4286
+ }
4287
+ function checkClientAcceptance(rule, senderId) {
4288
+ if (!rule || rule === "all") return true;
4289
+ if (rule === "none") return false;
4290
+ if (typeof rule === "object" && "include" in rule) {
4291
+ return rule.include.includes(senderId);
4292
+ }
4293
+ return false;
4294
+ }
4295
+ function checkSystemAcceptance(rule, senderSystemId) {
4296
+ if (!rule || rule === "all") return true;
4297
+ if (rule === "none") return false;
4298
+ if (typeof rule === "object" && "include" in rule) {
4299
+ return senderSystemId !== void 0 && rule.include.includes(senderSystemId);
4300
+ }
4301
+ return false;
4302
+ }
4303
+ function canAgentAcceptMessage(targetAgent, context, config = DEFAULT_AGENT_PERMISSION_CONFIG) {
4304
+ const permissions = resolveAgentPermissions(targetAgent, config);
4305
+ const acceptsFrom = permissions.acceptsFrom;
4306
+ if (!acceptsFrom) return true;
4307
+ switch (context.senderType) {
4308
+ case "agent":
4309
+ return checkAgentAcceptance(acceptsFrom.agents, context);
4310
+ case "client":
4311
+ return checkClientAcceptance(acceptsFrom.clients, context.senderId);
4312
+ case "system":
4313
+ case "gateway":
4314
+ return checkSystemAcceptance(acceptsFrom.systems, context.senderSystemId);
4315
+ default:
4316
+ return false;
4317
+ }
4318
+ }
4319
+ function canAgentSeeAgent(viewerAgent, targetAgentId, context, config = DEFAULT_AGENT_PERMISSION_CONFIG) {
4320
+ const permissions = resolveAgentPermissions(viewerAgent, config);
4321
+ const canSee = permissions.canSee?.agents;
4322
+ if (!canSee || canSee === "all") return true;
4323
+ if (canSee === "hierarchy") {
4324
+ return context.isParent === true || context.isChild === true || context.isAncestor === true || context.isDescendant === true;
4325
+ }
4326
+ if (canSee === "scoped") {
4327
+ return (context.sharedScopes?.length ?? 0) > 0;
4328
+ }
4329
+ if (canSee === "direct") {
4330
+ return false;
4331
+ }
4332
+ if (typeof canSee === "object" && "include" in canSee) {
4333
+ return canSee.include.includes(targetAgentId);
4334
+ }
4335
+ return false;
4336
+ }
4337
+ function canAgentMessageAgent(senderAgent, targetAgentId, context, config = DEFAULT_AGENT_PERMISSION_CONFIG) {
4338
+ const permissions = resolveAgentPermissions(senderAgent, config);
4339
+ const canMessage = permissions.canMessage?.agents;
4340
+ if (!canMessage || canMessage === "all") return true;
4341
+ if (canMessage === "hierarchy") {
4342
+ return context.isParent === true || context.isChild === true || context.isAncestor === true || context.isDescendant === true;
4343
+ }
4344
+ if (canMessage === "scoped") {
4345
+ return (context.sharedScopes?.length ?? 0) > 0;
4346
+ }
4347
+ if (typeof canMessage === "object" && "include" in canMessage) {
4348
+ return canMessage.include.includes(targetAgentId);
4349
+ }
4350
+ return false;
4351
+ }
4352
+
4353
+ Object.defineProperty(exports, "monotonicFactory", {
4354
+ enumerable: true,
4355
+ get: function () { return ulid.monotonicFactory; }
4356
+ });
4357
+ Object.defineProperty(exports, "ulid", {
4358
+ enumerable: true,
4359
+ get: function () { return ulid.ulid; }
4360
+ });
4361
+ exports.AGENT_ERROR_CODES = AGENT_ERROR_CODES;
4362
+ exports.AUTH_ERROR_CODES = AUTH_ERROR_CODES;
4363
+ exports.AUTH_METHODS = AUTH_METHODS;
4364
+ exports.AddressSchema = AddressSchema;
4365
+ exports.AgentConnection = AgentConnection;
4366
+ exports.AgentIdSchema = AgentIdSchema;
4367
+ exports.AgentLifecycleSchema = AgentLifecycleSchema;
4368
+ exports.AgentRelationshipSchema = AgentRelationshipSchema;
4369
+ exports.AgentSchema = AgentSchema;
4370
+ exports.AgentStateSchema = AgentStateSchema;
4371
+ exports.AgentVisibilitySchema = AgentVisibilitySchema;
4372
+ exports.BaseConnection = BaseConnection;
4373
+ exports.BroadcastAddressSchema = BroadcastAddressSchema;
4374
+ exports.CAPABILITY_REQUIREMENTS = CAPABILITY_REQUIREMENTS;
4375
+ exports.CORE_METHODS = CORE_METHODS;
4376
+ exports.CausalEventBuffer = CausalEventBuffer;
4377
+ exports.ClientConnection = ClientConnection;
4378
+ exports.CorrelationIdSchema = CorrelationIdSchema;
4379
+ exports.DEFAULT_AGENT_PERMISSION_CONFIG = DEFAULT_AGENT_PERMISSION_CONFIG;
4380
+ exports.DEFAULT_RETRY_POLICY = DEFAULT_RETRY_POLICY;
4381
+ exports.DeliverySemanticsSchema = DeliverySemanticsSchema;
4382
+ exports.DirectAddressSchema = DirectAddressSchema;
4383
+ exports.ERROR_CODES = ERROR_CODES;
4384
+ exports.EVENT_TYPES = EVENT_TYPES;
4385
+ exports.EXTENSION_METHODS = EXTENSION_METHODS;
4386
+ exports.ErrorCategorySchema = ErrorCategorySchema;
4387
+ exports.EventSchema = EventSchema;
4388
+ exports.EventTypeSchema = EventTypeSchema;
4389
+ exports.FEDERATION_ERROR_CODES = FEDERATION_ERROR_CODES;
4390
+ exports.FEDERATION_METHODS = FEDERATION_METHODS;
4391
+ exports.FederatedAddressSchema = FederatedAddressSchema;
4392
+ exports.FederationOutageBuffer = FederationOutageBuffer;
4393
+ exports.GatewayConnection = GatewayConnection;
4394
+ exports.HierarchicalAddressSchema = HierarchicalAddressSchema;
4395
+ exports.JSONRPC_VERSION = JSONRPC_VERSION;
4396
+ exports.JsonRpcVersionSchema = JsonRpcVersionSchema;
4397
+ exports.LIFECYCLE_METHODS = LIFECYCLE_METHODS;
4398
+ exports.MAPConnectionError = MAPConnectionError;
4399
+ exports.MAPErrorDataSchema = MAPErrorDataSchema;
4400
+ exports.MAPErrorSchema = MAPErrorSchema;
4401
+ exports.MAPNotificationSchema = MAPNotificationSchema;
4402
+ exports.MAPRequestError = MAPRequestError;
4403
+ exports.MAPRequestSchema = MAPRequestSchema;
4404
+ exports.MAPResponseErrorSchema = MAPResponseErrorSchema;
4405
+ exports.MAPResponseSchema = MAPResponseSchema;
4406
+ exports.MAPResponseSuccessSchema = MAPResponseSuccessSchema;
4407
+ exports.MAPTimeoutError = MAPTimeoutError;
4408
+ exports.MAP_METHODS = MAP_METHODS;
4409
+ exports.METHOD_REGISTRY = METHOD_REGISTRY;
4410
+ exports.MessageIdSchema = MessageIdSchema;
4411
+ exports.MessageMetaSchema = MessageMetaSchema;
4412
+ exports.MessagePrioritySchema = MessagePrioritySchema;
4413
+ exports.MessageRelationshipSchema = MessageRelationshipSchema;
4414
+ exports.MessageSchema = MessageSchema;
4415
+ exports.MessageVisibilitySchema = MessageVisibilitySchema;
4416
+ exports.MetaSchema = MetaSchema;
4417
+ exports.MultiAddressSchema = MultiAddressSchema;
4418
+ exports.NOTIFICATION_METHODS = NOTIFICATION_METHODS;
4419
+ exports.OBSERVATION_METHODS = OBSERVATION_METHODS;
4420
+ exports.PERMISSION_METHODS = PERMISSION_METHODS;
4421
+ exports.PROTOCOL_ERROR_CODES = PROTOCOL_ERROR_CODES;
4422
+ exports.PROTOCOL_VERSION = PROTOCOL_VERSION;
4423
+ exports.ParticipantAddressSchema = ParticipantAddressSchema;
4424
+ exports.ParticipantCapabilitiesSchema = ParticipantCapabilitiesSchema;
4425
+ exports.ParticipantIdSchema = ParticipantIdSchema;
4426
+ exports.ParticipantTypeSchema = ParticipantTypeSchema;
4427
+ exports.ProtocolVersionSchema = ProtocolVersionSchema;
4428
+ exports.RESOURCE_ERROR_CODES = RESOURCE_ERROR_CODES;
4429
+ exports.ROUTING_ERROR_CODES = ROUTING_ERROR_CODES;
4430
+ exports.RequestIdSchema = RequestIdSchema;
4431
+ exports.RoleAddressSchema = RoleAddressSchema;
4432
+ exports.SCOPE_METHODS = SCOPE_METHODS;
4433
+ exports.SESSION_METHODS = SESSION_METHODS;
4434
+ exports.STATE_METHODS = STATE_METHODS;
4435
+ exports.STEERING_METHODS = STEERING_METHODS;
4436
+ exports.STRUCTURE_METHODS = STRUCTURE_METHODS;
4437
+ exports.ScopeAddressSchema = ScopeAddressSchema;
4438
+ exports.ScopeIdSchema = ScopeIdSchema;
4439
+ exports.ScopeJoinPolicySchema = ScopeJoinPolicySchema;
4440
+ exports.ScopeSchema = ScopeSchema;
4441
+ exports.ScopeSendPolicySchema = ScopeSendPolicySchema;
4442
+ exports.ScopeVisibilitySchema = ScopeVisibilitySchema;
4443
+ exports.SessionIdSchema = SessionIdSchema;
4444
+ exports.Subscription = Subscription;
4445
+ exports.SubscriptionFilterSchema = SubscriptionFilterSchema;
4446
+ exports.SubscriptionIdSchema = SubscriptionIdSchema;
4447
+ exports.SystemAddressSchema = SystemAddressSchema;
4448
+ exports.TimestampSchema = TimestampSchema;
4449
+ exports.TransportTypeSchema = TransportTypeSchema;
4450
+ exports.buildAgentsGetResponse = buildAgentsGetResponse;
4451
+ exports.buildAgentsListResponse = buildAgentsListResponse;
4452
+ exports.buildAgentsRegisterResponse = buildAgentsRegisterResponse;
4453
+ exports.buildAgentsSpawnResponse = buildAgentsSpawnResponse;
4454
+ exports.buildAgentsUnregisterResponse = buildAgentsUnregisterResponse;
4455
+ exports.buildAgentsUpdateResponse = buildAgentsUpdateResponse;
4456
+ exports.buildConnectResponse = buildConnectResponse;
4457
+ exports.buildDisconnectResponse = buildDisconnectResponse;
4458
+ exports.buildScopesCreateResponse = buildScopesCreateResponse;
4459
+ exports.buildScopesJoinResponse = buildScopesJoinResponse;
4460
+ exports.buildScopesLeaveResponse = buildScopesLeaveResponse;
4461
+ exports.buildScopesListResponse = buildScopesListResponse;
4462
+ exports.buildSendResponse = buildSendResponse;
4463
+ exports.buildSubscribeResponse = buildSubscribeResponse;
4464
+ exports.buildUnsubscribeResponse = buildUnsubscribeResponse;
4465
+ exports.calculateDelay = calculateDelay;
4466
+ exports.canAgentAcceptMessage = canAgentAcceptMessage;
4467
+ exports.canAgentMessageAgent = canAgentMessageAgent;
4468
+ exports.canAgentSeeAgent = canAgentSeeAgent;
4469
+ exports.canControlAgent = canControlAgent;
4470
+ exports.canJoinScope = canJoinScope;
4471
+ exports.canMessageAgent = canMessageAgent;
4472
+ exports.canPerformAction = canPerformAction;
4473
+ exports.canPerformMethod = canPerformMethod;
4474
+ exports.canSeeAgent = canSeeAgent;
4475
+ exports.canSeeScope = canSeeScope;
4476
+ exports.canSendToScope = canSendToScope;
4477
+ exports.compareUlid = compareUlid;
4478
+ exports.createErrorResponse = createErrorResponse;
4479
+ exports.createEvent = createEvent;
4480
+ exports.createFederationEnvelope = createFederationEnvelope;
4481
+ exports.createNotification = createNotification;
4482
+ exports.createRequest = createRequest;
4483
+ exports.createRetryPolicy = createRetryPolicy;
4484
+ exports.createStreamPair = createStreamPair;
4485
+ exports.createSubscription = createSubscription;
4486
+ exports.createSuccessResponse = createSuccessResponse;
4487
+ exports.deepMergePermissions = deepMergePermissions;
4488
+ exports.filterVisibleAgents = filterVisibleAgents;
4489
+ exports.filterVisibleEvents = filterVisibleEvents;
4490
+ exports.filterVisibleScopes = filterVisibleScopes;
4491
+ exports.getEnvelopeRoutingInfo = getEnvelopeRoutingInfo;
4492
+ exports.getMethodInfo = getMethodInfo;
4493
+ exports.getMethodsByCategory = getMethodsByCategory;
4494
+ exports.getRequiredCapabilities = getRequiredCapabilities;
4495
+ exports.hasCapability = hasCapability;
4496
+ exports.hasRequiredCapabilities = hasRequiredCapabilities;
4497
+ exports.isAgentExposed = isAgentExposed;
4498
+ exports.isBroadcastAddress = isBroadcastAddress;
4499
+ exports.isDirectAddress = isDirectAddress;
4500
+ exports.isEnvelopeAtDestination = isEnvelopeAtDestination;
4501
+ exports.isErrorResponse = isErrorResponse;
4502
+ exports.isEventTypeExposed = isEventTypeExposed;
4503
+ exports.isFederatedAddress = isFederatedAddress;
4504
+ exports.isHierarchicalAddress = isHierarchicalAddress;
4505
+ exports.isNotification = isNotification;
4506
+ exports.isOrphanedAgent = isOrphanedAgent;
4507
+ exports.isRequest = isRequest;
4508
+ exports.isResponse = isResponse;
4509
+ exports.isScopeAddress = isScopeAddress;
4510
+ exports.isScopeExposed = isScopeExposed;
4511
+ exports.isSuccessResponse = isSuccessResponse;
4512
+ exports.isValidEnvelope = isValidEnvelope;
4513
+ exports.isValidUlid = isValidUlid;
4514
+ exports.mapVisibilityToRule = mapVisibilityToRule;
4515
+ exports.ndJsonStream = ndJsonStream;
4516
+ exports.processFederationEnvelope = processFederationEnvelope;
4517
+ exports.resolveAgentPermissions = resolveAgentPermissions;
4518
+ exports.retryable = retryable;
4519
+ exports.sleep = sleep;
4520
+ exports.sortCausalOrder = sortCausalOrder;
4521
+ exports.ulidTimestamp = ulidTimestamp;
4522
+ exports.unwrapEnvelope = unwrapEnvelope;
4523
+ exports.validateCausalOrder = validateCausalOrder;
4524
+ exports.websocketStream = websocketStream;
4525
+ exports.withPayload = withPayload;
4526
+ exports.withRetry = withRetry;
4527
+ //# sourceMappingURL=index.cjs.map
4528
+ //# sourceMappingURL=index.cjs.map