@contextvm/sdk 0.11.7 → 0.11.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/dist/esm/core/utils/base64.d.ts +3 -0
  2. package/dist/esm/core/utils/base64.d.ts.map +1 -0
  3. package/dist/esm/core/utils/base64.js +24 -0
  4. package/dist/esm/core/utils/base64.js.map +1 -0
  5. package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.d.ts.map +1 -1
  6. package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.js +2 -1
  7. package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.js.map +1 -1
  8. package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.d.ts.map +1 -1
  9. package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.js +2 -1
  10. package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.js.map +1 -1
  11. package/dist/esm/transport/capability-negotiator.d.ts +141 -0
  12. package/dist/esm/transport/capability-negotiator.d.ts.map +1 -0
  13. package/dist/esm/transport/capability-negotiator.js +198 -0
  14. package/dist/esm/transport/capability-negotiator.js.map +1 -0
  15. package/dist/esm/transport/middleware.d.ts +9 -0
  16. package/dist/esm/transport/middleware.d.ts.map +1 -0
  17. package/dist/esm/transport/middleware.js +2 -0
  18. package/dist/esm/transport/middleware.js.map +1 -0
  19. package/dist/esm/transport/nostr-client/event-pipeline.d.ts +29 -0
  20. package/dist/esm/transport/nostr-client/event-pipeline.d.ts.map +1 -0
  21. package/dist/esm/transport/nostr-client/event-pipeline.js +109 -0
  22. package/dist/esm/transport/nostr-client/event-pipeline.js.map +1 -0
  23. package/dist/esm/transport/nostr-client/inbound-coordinator.d.ts +37 -0
  24. package/dist/esm/transport/nostr-client/inbound-coordinator.d.ts.map +1 -0
  25. package/dist/esm/transport/nostr-client/inbound-coordinator.js +159 -0
  26. package/dist/esm/transport/nostr-client/inbound-coordinator.js.map +1 -0
  27. package/dist/esm/transport/nostr-client/inbound-notification-dispatcher.d.ts +28 -0
  28. package/dist/esm/transport/nostr-client/inbound-notification-dispatcher.d.ts.map +1 -0
  29. package/dist/esm/transport/nostr-client/inbound-notification-dispatcher.js +65 -0
  30. package/dist/esm/transport/nostr-client/inbound-notification-dispatcher.js.map +1 -0
  31. package/dist/esm/transport/nostr-client/open-stream-factory.d.ts +36 -0
  32. package/dist/esm/transport/nostr-client/open-stream-factory.d.ts.map +1 -0
  33. package/dist/esm/transport/nostr-client/open-stream-factory.js +126 -0
  34. package/dist/esm/transport/nostr-client/open-stream-factory.js.map +1 -0
  35. package/dist/esm/transport/nostr-client/outbound-sender.d.ts +45 -0
  36. package/dist/esm/transport/nostr-client/outbound-sender.d.ts.map +1 -0
  37. package/dist/esm/transport/nostr-client/outbound-sender.js +105 -0
  38. package/dist/esm/transport/nostr-client/outbound-sender.js.map +1 -0
  39. package/dist/esm/transport/nostr-client/server-metadata-store.d.ts +35 -0
  40. package/dist/esm/transport/nostr-client/server-metadata-store.d.ts.map +1 -0
  41. package/dist/esm/transport/nostr-client/server-metadata-store.js +107 -0
  42. package/dist/esm/transport/nostr-client/server-metadata-store.js.map +1 -0
  43. package/dist/esm/transport/nostr-client-transport.d.ts +18 -41
  44. package/dist/esm/transport/nostr-client-transport.d.ts.map +1 -1
  45. package/dist/esm/transport/nostr-client-transport.js +117 -553
  46. package/dist/esm/transport/nostr-client-transport.js.map +1 -1
  47. package/dist/esm/transport/nostr-server/correlation-store.d.ts +2 -2
  48. package/dist/esm/transport/nostr-server/correlation-store.d.ts.map +1 -1
  49. package/dist/esm/transport/nostr-server/correlation-store.js +12 -3
  50. package/dist/esm/transport/nostr-server/correlation-store.js.map +1 -1
  51. package/dist/esm/transport/nostr-server/event-pipeline.d.ts +32 -0
  52. package/dist/esm/transport/nostr-server/event-pipeline.d.ts.map +1 -0
  53. package/dist/esm/transport/nostr-server/event-pipeline.js +118 -0
  54. package/dist/esm/transport/nostr-server/event-pipeline.js.map +1 -0
  55. package/dist/esm/transport/nostr-server/inbound-coordinator.d.ts +56 -0
  56. package/dist/esm/transport/nostr-server/inbound-coordinator.d.ts.map +1 -0
  57. package/dist/esm/transport/nostr-server/inbound-coordinator.js +168 -0
  58. package/dist/esm/transport/nostr-server/inbound-coordinator.js.map +1 -0
  59. package/dist/esm/transport/nostr-server/inbound-notification-dispatcher.d.ts +44 -0
  60. package/dist/esm/transport/nostr-server/inbound-notification-dispatcher.d.ts.map +1 -0
  61. package/dist/esm/transport/nostr-server/inbound-notification-dispatcher.js +153 -0
  62. package/dist/esm/transport/nostr-server/inbound-notification-dispatcher.js.map +1 -0
  63. package/dist/esm/transport/nostr-server/open-stream-factory.d.ts +81 -0
  64. package/dist/esm/transport/nostr-server/open-stream-factory.d.ts.map +1 -0
  65. package/dist/esm/transport/nostr-server/open-stream-factory.js +224 -0
  66. package/dist/esm/transport/nostr-server/open-stream-factory.js.map +1 -0
  67. package/dist/esm/transport/nostr-server/outbound-notification-broadcaster.d.ts +24 -0
  68. package/dist/esm/transport/nostr-server/outbound-notification-broadcaster.d.ts.map +1 -0
  69. package/dist/esm/transport/nostr-server/outbound-notification-broadcaster.js +64 -0
  70. package/dist/esm/transport/nostr-server/outbound-notification-broadcaster.js.map +1 -0
  71. package/dist/esm/transport/nostr-server/outbound-response-router.d.ts +62 -0
  72. package/dist/esm/transport/nostr-server/outbound-response-router.d.ts.map +1 -0
  73. package/dist/esm/transport/nostr-server/outbound-response-router.js +125 -0
  74. package/dist/esm/transport/nostr-server/outbound-response-router.js.map +1 -0
  75. package/dist/esm/transport/nostr-server-transport.d.ts +15 -62
  76. package/dist/esm/transport/nostr-server-transport.d.ts.map +1 -1
  77. package/dist/esm/transport/nostr-server-transport.js +121 -741
  78. package/dist/esm/transport/nostr-server-transport.js.map +1 -1
  79. package/dist/esm/transport/open-stream/registry.d.ts.map +1 -1
  80. package/dist/esm/transport/open-stream/registry.js +7 -1
  81. package/dist/esm/transport/open-stream/registry.js.map +1 -1
  82. package/dist/esm/transport/open-stream/session.d.ts +1 -0
  83. package/dist/esm/transport/open-stream/session.d.ts.map +1 -1
  84. package/dist/esm/transport/open-stream/session.js +14 -4
  85. package/dist/esm/transport/open-stream/session.js.map +1 -1
  86. package/dist/esm/transport/open-stream/writer.d.ts.map +1 -1
  87. package/dist/esm/transport/open-stream/writer.js +6 -12
  88. package/dist/esm/transport/open-stream/writer.js.map +1 -1
  89. package/package.json +1 -1
@@ -1,9 +1,7 @@
1
- import { InitializeResultSchema, ListPromptsResultSchema, ListResourcesResultSchema, ListResourceTemplatesResultSchema, ListToolsResultSchema, isJSONRPCRequest, isJSONRPCNotification, isJSONRPCResultResponse, isJSONRPCErrorResponse, } from '@modelcontextprotocol/sdk/types.js';
1
+ import { isJSONRPCNotification, isJSONRPCResultResponse, isJSONRPCErrorResponse, } from '@modelcontextprotocol/sdk/types.js';
2
2
  import { BaseNostrTransport, } from './base-nostr-transport.js';
3
- import { CTXVM_MESSAGES_KIND, DEFAULT_TIMEOUT_MS, EPHEMERAL_GIFT_WRAP_KIND, GIFT_WRAP_KIND, NOSTR_TAGS, NOTIFICATIONS_INITIALIZED_METHOD, decryptMessage, DEFAULT_LRU_SIZE, } from '../core/index.js';
4
- import { EncryptionMode, GiftWrapMode } from '../core/interfaces.js';
5
- import { verifyEvent } from 'nostr-tools/pure';
6
- import { injectClientPubkey, injectRequestEventId, withTimeout, } from '../core/utils/utils.js';
3
+ import { CTXVM_MESSAGES_KIND, DEFAULT_TIMEOUT_MS, NOSTR_TAGS, DEFAULT_LRU_SIZE, } from '../core/index.js';
4
+ import { withTimeout } from '../core/utils/utils.js';
7
5
  import { CorrelationStore } from './nostr-server/correlation-store.js';
8
6
  import { SessionStore } from './nostr-server/session-store.js';
9
7
  import { LruCache } from '../core/utils/lru-cache.js';
@@ -11,10 +9,14 @@ import { ApplesauceRelayPool } from '../relay/applesauce-relay-pool.js';
11
9
  import { AuthorizationPolicy, } from './nostr-server/authorization-policy.js';
12
10
  import { AnnouncementManager, } from './nostr-server/announcement-manager.js';
13
11
  import { OversizedTransferReceiver, } from './oversized-transfer/index.js';
14
- import { OpenStreamReceiver, OpenStreamWriter, buildOpenStreamAcceptFrame, buildOpenStreamAbortFrame, buildOpenStreamPingFrame, buildOpenStreamPongFrame, } from './open-stream/index.js';
15
12
  import { DEFAULT_CHUNK_SIZE, DEFAULT_OVERSIZED_THRESHOLD, } from './oversized-transfer/constants.js';
16
- import { learnPeerCapabilities } from './discovery-tags.js';
17
- import { sendAcceptFrame, sendOversizedServerResponse, } from './nostr-server/oversized-server-handler.js';
13
+ import { ServerCapabilityNegotiator } from './capability-negotiator.js';
14
+ import { InboundNotificationDispatcher } from './nostr-server/inbound-notification-dispatcher.js';
15
+ import { OutboundResponseRouter } from './nostr-server/outbound-response-router.js';
16
+ import { OutboundNotificationBroadcaster } from './nostr-server/outbound-notification-broadcaster.js';
17
+ import { ServerOpenStreamFactory } from './nostr-server/open-stream-factory.js';
18
+ import { ServerEventPipeline } from './nostr-server/event-pipeline.js';
19
+ import { ServerInboundCoordinator } from './nostr-server/inbound-coordinator.js';
18
20
  /**
19
21
  * A server-side transport layer for CTXVM that uses Nostr events for communication.
20
22
  * This transport listens for incoming MCP requests via Nostr events and can send
@@ -23,7 +25,7 @@ import { sendAcceptFrame, sendOversizedServerResponse, } from './nostr-server/ov
23
25
  */
24
26
  export class NostrServerTransport extends BaseNostrTransport {
25
27
  constructor(options) {
26
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x;
28
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
27
29
  super('nostr-server-transport', options);
28
30
  this.inboundMiddlewares = [];
29
31
  this.listToolsResultTransformers = [];
@@ -34,14 +36,6 @@ export class NostrServerTransport extends BaseNostrTransport {
34
36
  * Used for gift-wrap envelopes (outer event ids) and decrypted inner events.
35
37
  */
36
38
  this.seenEventIds = new LruCache(DEFAULT_LRU_SIZE);
37
- /** Pending final responses held until their CEP-41 stream terminates. */
38
- this.pendingOpenStreamResponses = new Map();
39
- /** Sessions logically evicted after CEP-41 probe timeout, retained only to flush deferred finals. */
40
- this.pendingOpenStreamSessionEvictions = new Map();
41
- /** Client pubkeys that should no longer receive new notifications. */
42
- this.evictedOpenStreamClientPubkeys = new Set();
43
- /** Active server-side CEP-41 writers keyed by inbound request event id. */
44
- this.openStreamWriters = new Map();
45
39
  this.injectClientPubkey = (_a = options.injectClientPubkey) !== null && _a !== void 0 ? _a : false;
46
40
  this.shouldInjectRequestEventId = (_b = options.injectRequestEventId) !== null && _b !== void 0 ? _b : false;
47
41
  this.onClientSessionEvicted = options.onClientSessionEvicted;
@@ -120,56 +114,6 @@ export class NostrServerTransport extends BaseNostrTransport {
120
114
  this.oversizedChunkSize = (_g = ot === null || ot === void 0 ? void 0 : ot.chunkSizeBytes) !== null && _g !== void 0 ? _g : DEFAULT_CHUNK_SIZE;
121
115
  this.oversizedReceiver = new OversizedTransferReceiver((_h = ot === null || ot === void 0 ? void 0 : ot.policy) !== null && _h !== void 0 ? _h : {}, this.logger);
122
116
  this.openStreamEnabled = (_k = (_j = options.openStream) === null || _j === void 0 ? void 0 : _j.enabled) !== null && _k !== void 0 ? _k : false;
123
- this.openStreamReceiver = new OpenStreamReceiver({
124
- maxConcurrentStreams: (_m = (_l = options.openStream) === null || _l === void 0 ? void 0 : _l.policy) === null || _m === void 0 ? void 0 : _m.maxConcurrentStreams,
125
- maxBufferedChunksPerStream: (_p = (_o = options.openStream) === null || _o === void 0 ? void 0 : _o.policy) === null || _p === void 0 ? void 0 : _p.maxBufferedChunksPerStream,
126
- maxBufferedBytesPerStream: (_r = (_q = options.openStream) === null || _q === void 0 ? void 0 : _q.policy) === null || _r === void 0 ? void 0 : _r.maxBufferedBytesPerStream,
127
- idleTimeoutMs: (_t = (_s = options.openStream) === null || _s === void 0 ? void 0 : _s.policy) === null || _t === void 0 ? void 0 : _t.idleTimeoutMs,
128
- probeTimeoutMs: (_v = (_u = options.openStream) === null || _u === void 0 ? void 0 : _u.policy) === null || _v === void 0 ? void 0 : _v.probeTimeoutMs,
129
- closeGracePeriodMs: (_x = (_w = options.openStream) === null || _w === void 0 ? void 0 : _w.policy) === null || _x === void 0 ? void 0 : _x.closeGracePeriodMs,
130
- getSessionOptions: (progressToken) => {
131
- let progress = 0;
132
- return {
133
- sendPing: async (nonce) => {
134
- progress += 1;
135
- await this.sendNotification(progressToken, {
136
- jsonrpc: '2.0',
137
- method: 'notifications/progress',
138
- params: buildOpenStreamPingFrame({
139
- progressToken,
140
- progress,
141
- nonce,
142
- }),
143
- });
144
- },
145
- sendPong: async (nonce) => {
146
- progress += 1;
147
- await this.sendNotification(progressToken, {
148
- jsonrpc: '2.0',
149
- method: 'notifications/progress',
150
- params: buildOpenStreamPongFrame({
151
- progressToken,
152
- progress,
153
- nonce,
154
- }),
155
- });
156
- },
157
- sendAbort: async (reason) => {
158
- progress += 1;
159
- await this.sendNotification(progressToken, {
160
- jsonrpc: '2.0',
161
- method: 'notifications/progress',
162
- params: buildOpenStreamAbortFrame({
163
- progressToken,
164
- progress,
165
- reason,
166
- }),
167
- });
168
- },
169
- };
170
- },
171
- logger: this.logger,
172
- });
173
117
  // Advertise CEP-22 support so clients can skip the accept handshake.
174
118
  const internalCommonTags = [];
175
119
  if (this.oversizedEnabled) {
@@ -179,6 +123,97 @@ export class NostrServerTransport extends BaseNostrTransport {
179
123
  internalCommonTags.push([NOSTR_TAGS.SUPPORT_OPEN_STREAM]);
180
124
  }
181
125
  this.announcementManager.setInternalCommonTags(internalCommonTags);
126
+ this.capabilityNegotiator = new ServerCapabilityNegotiator({
127
+ getCommonTags: this.announcementManager.getCommonTags.bind(this.announcementManager),
128
+ composeOutboundTags: this.composeOutboundTags.bind(this),
129
+ giftWrapMode: this.giftWrapMode,
130
+ });
131
+ this.openStreamFactory = new ServerOpenStreamFactory({
132
+ openStreamEnabled: this.openStreamEnabled,
133
+ sendNotification: this.sendNotification.bind(this),
134
+ handleResponse: async (response) => {
135
+ await this.outboundResponseRouter.route(response);
136
+ },
137
+ sessionStore: this.sessionStore,
138
+ onClientSessionEvicted: this.onClientSessionEvicted,
139
+ correlationStore: this.correlationStore,
140
+ policy: (_l = options.openStream) === null || _l === void 0 ? void 0 : _l.policy,
141
+ logger: this.logger,
142
+ });
143
+ this.inboundCoordinator = new ServerInboundCoordinator({
144
+ sessionStore: this.sessionStore,
145
+ correlationStore: this.correlationStore,
146
+ authorizationPolicy: this.authorizationPolicy,
147
+ openStreamFactory: this.openStreamFactory,
148
+ inboundMiddlewares: this.inboundMiddlewares,
149
+ injectClientPubkey: this.injectClientPubkey,
150
+ shouldInjectRequestEventId: this.shouldInjectRequestEventId,
151
+ oversizedEnabled: this.oversizedEnabled,
152
+ openStreamEnabled: this.openStreamEnabled,
153
+ giftWrapMode: this.giftWrapMode,
154
+ sendMcpMessage: this.sendMcpMessage.bind(this),
155
+ createResponseTags: (clientPubkey, requestId) => this.createResponseTags(clientPubkey, String(requestId)),
156
+ getOrCreateClientSession: this.getOrCreateClientSession.bind(this),
157
+ forwardMessage: async (msg, clientPubkey) => {
158
+ var _a, _b;
159
+ (_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, msg);
160
+ (_b = this.onmessageWithContext) === null || _b === void 0 ? void 0 : _b.call(this, msg, { clientPubkey });
161
+ return true;
162
+ },
163
+ logger: this.logger,
164
+ onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
165
+ });
166
+ this.inboundNotificationDispatcher = new InboundNotificationDispatcher({
167
+ openStreamReceiver: this.openStreamFactory.getReceiver(),
168
+ oversizedReceiver: this.oversizedReceiver,
169
+ openStreamFactory: this.openStreamFactory,
170
+ correlationStore: this.correlationStore,
171
+ sendNotification: this.sendNotification.bind(this),
172
+ handleIncomingRequest: this.inboundCoordinator.handleIncomingRequest.bind(this.inboundCoordinator),
173
+ handleIncomingNotification: this.inboundCoordinator.handleIncomingNotification.bind(this.inboundCoordinator),
174
+ cleanupDroppedRequest: this.inboundCoordinator.cleanupDroppedRequest.bind(this.inboundCoordinator),
175
+ shouldInjectRequestEventId: this.shouldInjectRequestEventId,
176
+ injectClientPubkey: this.injectClientPubkey,
177
+ logger: this.logger,
178
+ onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
179
+ });
180
+ this.inboundCoordinator.setNotificationDispatcher(this.inboundNotificationDispatcher);
181
+ this.outboundResponseRouter = new OutboundResponseRouter({
182
+ correlationStore: this.correlationStore,
183
+ sessionStore: this.sessionStore,
184
+ announcementManager: this.announcementManager,
185
+ openStreamFactory: this.openStreamFactory,
186
+ oversizedConfig: {
187
+ enabled: this.oversizedEnabled,
188
+ threshold: this.oversizedThreshold,
189
+ chunkSize: this.oversizedChunkSize,
190
+ },
191
+ applyListToolsResultTransformers: this.applyListToolsResultTransformers.bind(this),
192
+ buildOutboundTags: this.capabilityNegotiator.buildOutboundTags.bind(this.capabilityNegotiator),
193
+ createResponseTags: this.createResponseTags.bind(this),
194
+ chooseGiftWrapKind: this.capabilityNegotiator.chooseOutboundGiftWrapKind.bind(this.capabilityNegotiator),
195
+ sendMcpMessage: this.sendMcpMessage.bind(this),
196
+ measurePublishedMcpMessageSize: this.measurePublishedMcpMessageSize.bind(this),
197
+ resolveSafeOversizedChunkSize: this.resolveSafeOversizedChunkSize.bind(this),
198
+ logger: this.logger,
199
+ onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
200
+ });
201
+ this.outboundNotificationBroadcaster = new OutboundNotificationBroadcaster({
202
+ correlationStore: this.correlationStore,
203
+ sessionStore: this.sessionStore,
204
+ sendNotification: this.sendNotification.bind(this),
205
+ enqueueTask: this.taskQueue.add.bind(this.taskQueue),
206
+ logger: this.logger,
207
+ onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
208
+ });
209
+ this.eventPipeline = new ServerEventPipeline({
210
+ signer: this.signer,
211
+ seenEventIds: this.seenEventIds,
212
+ encryptionMode: this.encryptionMode,
213
+ giftWrapMode: this.giftWrapMode,
214
+ logger: this.logger,
215
+ onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
216
+ });
182
217
  }
183
218
  /**
184
219
  * Sets extra tags to include in server announcement + initialize response events.
@@ -273,9 +308,8 @@ export class NostrServerTransport extends BaseNostrTransport {
273
308
  this.correlationStore.clear();
274
309
  this.seenEventIds.clear();
275
310
  this.oversizedReceiver.clear();
276
- this.openStreamReceiver.clear();
277
- this.pendingOpenStreamResponses.clear();
278
- this.openStreamWriters.clear();
311
+ this.openStreamFactory.getReceiver().clear();
312
+ this.openStreamFactory.clear();
279
313
  (_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
280
314
  }
281
315
  catch (error) {
@@ -332,39 +366,6 @@ export class NostrServerTransport extends BaseNostrTransport {
332
366
  }
333
367
  return session;
334
368
  }
335
- takePendingServerDiscoveryTags(session) {
336
- if (session.hasSentCommonTags) {
337
- return [];
338
- }
339
- session.hasSentCommonTags = true;
340
- return this.announcementManager.getCommonTags();
341
- }
342
- buildServerOutboundTags(params) {
343
- const { baseTags, session, includeDiscovery = true, negotiationTags = [], } = params;
344
- return this.composeOutboundTags({
345
- baseTags,
346
- discoveryTags: includeDiscovery
347
- ? this.takePendingServerDiscoveryTags(session)
348
- : [],
349
- negotiationTags,
350
- });
351
- }
352
- chooseServerOutboundGiftWrapKind(params) {
353
- const { session, fallbackWrapKind } = params;
354
- if (!session.isEncrypted) {
355
- return undefined;
356
- }
357
- if (this.giftWrapMode === GiftWrapMode.EPHEMERAL) {
358
- return EPHEMERAL_GIFT_WRAP_KIND;
359
- }
360
- if (this.giftWrapMode === GiftWrapMode.PERSISTENT) {
361
- return GIFT_WRAP_KIND;
362
- }
363
- if (session.supportsEphemeralEncryption) {
364
- return EPHEMERAL_GIFT_WRAP_KIND;
365
- }
366
- return fallbackWrapKind;
367
- }
368
369
  getRelayUrls(relayHandler) {
369
370
  return relayHandler.getRelayUrls();
370
371
  }
@@ -391,108 +392,6 @@ export class NostrServerTransport extends BaseNostrTransport {
391
392
  });
392
393
  }
393
394
  }
394
- /**
395
- * Handles incoming requests with correlation tracking.
396
- * @param eventId The Nostr event ID.
397
- * @param request The request message.
398
- * @param clientPubkey The client's public key.
399
- */
400
- handleIncomingRequest(event, eventId, request, clientPubkey, wrapKind) {
401
- var _a, _b;
402
- // Store the original request ID for later restoration
403
- const originalRequestId = request.id;
404
- // Use the unique Nostr event ID as the MCP request ID to avoid collisions
405
- request.id = eventId;
406
- // Register the event route in the correlation store
407
- const progressToken = (_b = (_a = request.params) === null || _a === void 0 ? void 0 : _a._meta) === null || _b === void 0 ? void 0 : _b.progressToken;
408
- this.correlationStore.registerEventRoute(eventId, clientPubkey, originalRequestId, progressToken ? String(progressToken) : undefined, wrapKind, this.shouldInjectRequestEventId ? event : undefined);
409
- if (this.openStreamEnabled && progressToken) {
410
- const writer = new OpenStreamWriter({
411
- progressToken: String(progressToken),
412
- publishFrame: async (frame) => {
413
- await this.sendNotification(clientPubkey, {
414
- jsonrpc: '2.0',
415
- method: 'notifications/progress',
416
- params: frame,
417
- });
418
- return undefined;
419
- },
420
- onClose: async () => {
421
- await this.flushPendingOpenStreamResponse(eventId);
422
- },
423
- onAbort: async (reason) => {
424
- await this.handleOpenStreamWriterAbort(clientPubkey, eventId, reason);
425
- },
426
- });
427
- this.openStreamWriters.set(eventId, writer);
428
- }
429
- }
430
- async flushPendingOpenStreamResponse(eventId) {
431
- const pendingResponse = this.pendingOpenStreamResponses.get(eventId);
432
- this.pendingOpenStreamResponses.delete(eventId);
433
- this.openStreamWriters.delete(eventId);
434
- if (!pendingResponse) {
435
- return;
436
- }
437
- await this.handleResponse(pendingResponse);
438
- }
439
- async handleOpenStreamWriterAbort(clientPubkey, eventId, reason) {
440
- if (reason === 'Probe timeout') {
441
- const session = this.sessionStore.getSession(clientPubkey);
442
- if (session) {
443
- this.pendingOpenStreamSessionEvictions.set(eventId, {
444
- clientPubkey,
445
- session: { ...session },
446
- });
447
- this.evictedOpenStreamClientPubkeys.add(clientPubkey);
448
- }
449
- const removed = this.sessionStore.removeSession(clientPubkey);
450
- if (removed || session) {
451
- this.logger.info('Removed session after open-stream probe timeout', {
452
- clientPubkey,
453
- eventId,
454
- });
455
- }
456
- }
457
- await this.flushPendingOpenStreamResponse(eventId);
458
- }
459
- finalizePendingOpenStreamSessionEviction(eventId) {
460
- const pendingEviction = this.pendingOpenStreamSessionEvictions.get(eventId);
461
- if (!pendingEviction) {
462
- return;
463
- }
464
- this.pendingOpenStreamSessionEvictions.delete(eventId);
465
- this.evictedOpenStreamClientPubkeys.delete(pendingEviction.clientPubkey);
466
- }
467
- findEventIdByProgressToken(progressToken) {
468
- for (const [clientPubkey] of this.sessionStore.getAllSessions()) {
469
- const eventId = this.correlationStore.getEventIdByProgressToken(clientPubkey, progressToken);
470
- if (eventId) {
471
- return eventId;
472
- }
473
- }
474
- return undefined;
475
- }
476
- /**
477
- * Cleans up request correlation for a request that was dropped by middleware.
478
- */
479
- cleanupDroppedRequest(message) {
480
- if (!isJSONRPCRequest(message)) {
481
- return;
482
- }
483
- this.correlationStore.popEventRoute(String(message.id));
484
- }
485
- /**
486
- * Handles incoming notifications.
487
- * @param clientPubkey The client's public key.
488
- * @param notification The notification message.
489
- */
490
- handleIncomingNotification(clientPubkey, notification) {
491
- if (isJSONRPCNotification(notification) &&
492
- notification.method === NOTIFICATIONS_INITIALIZED_METHOD) {
493
- this.sessionStore.markInitialized(clientPubkey);
494
- }
495
- }
496
395
  /**
497
396
  * Handles response messages by finding the original request and routing back to client.
498
397
  * @param response The JSON-RPC response or error to send.
@@ -504,183 +403,14 @@ export class NostrServerTransport extends BaseNostrTransport {
504
403
  return this.listToolsAnnouncementTagsProducers.flatMap((producer) => producer(result));
505
404
  }
506
405
  async handleResponse(response) {
507
- var _a, _b, _c;
508
- // Handle special announcement responses
509
- if (response.id === 'announcement') {
510
- const wasHandled = await this.announcementManager.handleAnnouncementResponse(response);
511
- if (wasHandled && isJSONRPCResultResponse(response)) {
512
- if (InitializeResultSchema.safeParse(response.result).success) {
513
- this.logger.info('Initialized');
514
- }
515
- }
516
- return;
517
- }
518
- // Find the event route using O(1) lookup
519
- const nostrEventId = response.id;
520
- const existingOpenStreamWriter = this.openStreamWriters.get(nostrEventId);
521
- if (existingOpenStreamWriter && existingOpenStreamWriter.isActive) {
522
- this.pendingOpenStreamResponses.set(nostrEventId, response);
523
- return;
524
- }
525
- const route = this.correlationStore.popEventRoute(nostrEventId);
526
- if (!route) {
527
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, new Error(`No pending request found for response ID: ${response.id}`));
528
- return;
529
- }
530
- const pendingEviction = this.pendingOpenStreamSessionEvictions.get(nostrEventId);
531
- const session = (_b = this.sessionStore.getSession(route.clientPubkey)) !== null && _b !== void 0 ? _b : pendingEviction === null || pendingEviction === void 0 ? void 0 : pendingEviction.session;
532
- if (!session) {
533
- (_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, new Error(`No session found for client: ${route.clientPubkey}`));
534
- return;
535
- }
536
- const parsedListToolsResult = isJSONRPCResultResponse(response)
537
- ? ListToolsResultSchema.safeParse(response.result)
538
- : null;
539
- const responseToSend = (parsedListToolsResult === null || parsedListToolsResult === void 0 ? void 0 : parsedListToolsResult.success)
540
- ? {
541
- ...response,
542
- result: this.applyListToolsResultTransformers(parsedListToolsResult.data),
543
- }
544
- : response;
545
- // Restore the original request ID in the response
546
- responseToSend.id = route.originalRequestId;
547
- // CEP-22 Oversized Transfer (proactive path for server responses)
548
- if (this.oversizedEnabled &&
549
- route.progressToken &&
550
- session.supportsOversizedTransfer) {
551
- // Serialize after restoring id so the client receives the original JSON-RPC id.
552
- const serialized = JSON.stringify(responseToSend);
553
- const continuationFrameTags = this.createResponseTags(route.clientPubkey, nostrEventId);
554
- const startFrameTags = this.buildServerOutboundTags({
555
- baseTags: continuationFrameTags,
556
- session,
557
- });
558
- const giftWrapKind = this.chooseServerOutboundGiftWrapKind({
559
- session,
560
- fallbackWrapKind: route.wrapKind,
561
- });
562
- const publishedEventSize = await this.measurePublishedMcpMessageSize(responseToSend, route.clientPubkey, CTXVM_MESSAGES_KIND, startFrameTags, session.isEncrypted, giftWrapKind);
563
- if (publishedEventSize > this.oversizedThreshold) {
564
- const chunkSizeBytes = await this.resolveSafeOversizedChunkSize({
565
- desiredChunkSizeBytes: this.oversizedChunkSize,
566
- maxPublishedEventBytes: this.oversizedThreshold,
567
- recipientPublicKey: route.clientPubkey,
568
- kind: CTXVM_MESSAGES_KIND,
569
- progressToken: route.progressToken,
570
- progress: 2,
571
- tags: continuationFrameTags,
572
- isEncrypted: session.isEncrypted,
573
- giftWrapKind,
574
- });
575
- try {
576
- await sendOversizedServerResponse({
577
- serialized,
578
- clientPubkey: route.clientPubkey,
579
- progressToken: route.progressToken,
580
- startFrameTags,
581
- continuationFrameTags,
582
- isEncrypted: session.isEncrypted,
583
- giftWrapKind,
584
- }, {
585
- chunkSizeBytes,
586
- }, {
587
- sendMcpMessage: this.sendMcpMessage.bind(this),
588
- logger: this.logger,
589
- });
590
- }
591
- catch (error) {
592
- this.correlationStore.registerEventRoute(nostrEventId, route.clientPubkey, route.originalRequestId, route.progressToken, route.wrapKind);
593
- throw error;
594
- }
595
- finally {
596
- this.finalizePendingOpenStreamSessionEviction(nostrEventId);
597
- }
598
- return;
599
- }
600
- }
601
- // Send the response back to the original requester
602
- const tags = this.buildServerOutboundTags({
603
- baseTags: this.createResponseTags(route.clientPubkey, nostrEventId),
604
- session,
605
- });
606
- const giftWrapKind = this.chooseServerOutboundGiftWrapKind({
607
- session,
608
- fallbackWrapKind: route.wrapKind,
609
- });
610
- // Attach pricing tags to capability list responses so clients can access CEP-8 pricing
611
- if (isJSONRPCResultResponse(responseToSend)) {
612
- const result = responseToSend.result;
613
- if (ListToolsResultSchema.safeParse(result).success ||
614
- ListResourcesResultSchema.safeParse(result).success ||
615
- ListResourceTemplatesResultSchema.safeParse(result).success ||
616
- ListPromptsResultSchema.safeParse(result).success) {
617
- tags.push(...this.announcementManager.getPricingTags());
618
- }
619
- }
620
- try {
621
- await this.sendMcpMessage(responseToSend, route.clientPubkey, CTXVM_MESSAGES_KIND, tags, session.isEncrypted, undefined, giftWrapKind);
622
- }
623
- catch (error) {
624
- this.correlationStore.registerEventRoute(nostrEventId, route.clientPubkey, route.originalRequestId, route.progressToken, route.wrapKind);
625
- throw error;
626
- }
627
- finally {
628
- this.finalizePendingOpenStreamSessionEviction(nostrEventId);
629
- }
406
+ await this.outboundResponseRouter.route(response);
630
407
  }
631
408
  /**
632
409
  * Handles notification messages with routing.
633
410
  * @param notification The JSON-RPC notification to send.
634
411
  */
635
412
  async handleNotification(notification) {
636
- var _a, _b, _c;
637
- try {
638
- // Special handling for progress notifications
639
- // TODO: Add handling for `notifications/resources/updated`, as they need to be associated with an id
640
- if (isJSONRPCNotification(notification) &&
641
- notification.method === 'notifications/progress' &&
642
- ((_a = notification.params) === null || _a === void 0 ? void 0 : _a.progressToken)) {
643
- const token = String(notification.params.progressToken);
644
- const nostrEventId = this.findEventIdByProgressToken(token);
645
- if (nostrEventId) {
646
- const route = this.correlationStore.getEventRoute(nostrEventId);
647
- if (route) {
648
- await this.sendNotification(route.clientPubkey, notification, nostrEventId);
649
- return;
650
- }
651
- }
652
- const error = new Error(`No client found for progress token: ${token}`);
653
- this.logger.error('Progress token not found', { token });
654
- (_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error);
655
- return;
656
- }
657
- // Use TaskQueue for outbound notification broadcasting to prevent event loop blocking
658
- for (const [clientPubkey, session,] of this.sessionStore.getAllSessions()) {
659
- if (session.isInitialized) {
660
- this.taskQueue.add(async () => {
661
- try {
662
- await this.sendNotification(clientPubkey, notification);
663
- }
664
- catch (error) {
665
- this.logger.error('Error sending notification', {
666
- error: error instanceof Error ? error.message : String(error),
667
- clientPubkey,
668
- method: isJSONRPCNotification(notification)
669
- ? notification.method
670
- : 'unknown',
671
- });
672
- }
673
- });
674
- }
675
- }
676
- }
677
- catch (error) {
678
- this.logger.error('Error in handleNotification', {
679
- error: error instanceof Error ? error.message : String(error),
680
- stack: error instanceof Error ? error.stack : undefined,
681
- });
682
- (_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, error instanceof Error ? error : new Error(String(error)));
683
- }
413
+ await this.outboundNotificationBroadcaster.broadcast(notification);
684
414
  }
685
415
  /**
686
416
  * Sends a notification to a specific client by their public key.
@@ -689,7 +419,7 @@ export class NostrServerTransport extends BaseNostrTransport {
689
419
  * @returns Promise that resolves when the notification is sent.
690
420
  */
691
421
  async sendNotification(clientPubkey, notification, correlatedEventId) {
692
- if (this.evictedOpenStreamClientPubkeys.has(clientPubkey)) {
422
+ if (this.openStreamFactory.isClientEvicted(clientPubkey)) {
693
423
  throw new Error(`No active session found for client: ${clientPubkey}`);
694
424
  }
695
425
  const session = this.sessionStore.getSession(clientPubkey);
@@ -700,11 +430,11 @@ export class NostrServerTransport extends BaseNostrTransport {
700
430
  if (correlatedEventId) {
701
431
  baseTags.push([NOSTR_TAGS.EVENT_ID, correlatedEventId]);
702
432
  }
703
- const tags = this.buildServerOutboundTags({
433
+ const tags = this.capabilityNegotiator.buildOutboundTags({
704
434
  baseTags,
705
435
  session,
706
436
  });
707
- const giftWrapKind = this.chooseServerOutboundGiftWrapKind({
437
+ const giftWrapKind = this.capabilityNegotiator.chooseOutboundGiftWrapKind({
708
438
  session,
709
439
  });
710
440
  await this.sendMcpMessage(notification, clientPubkey, CTXVM_MESSAGES_KIND, tags, session.isEncrypted, undefined, giftWrapKind);
@@ -716,369 +446,18 @@ export class NostrServerTransport extends BaseNostrTransport {
716
446
  * @param event The incoming Nostr event.
717
447
  */
718
448
  async processIncomingEvent(event) {
719
- var _a;
720
- try {
721
- if (event.kind === GIFT_WRAP_KIND ||
722
- event.kind === EPHEMERAL_GIFT_WRAP_KIND) {
723
- if (!this.isGiftWrapKindAllowed(event.kind)) {
724
- this.logger.debug('Skipping gift wrap due to GiftWrapMode policy', {
725
- eventId: event.id,
726
- kind: event.kind,
727
- });
728
- return;
729
- }
730
- // Deduplicate gift-wrap envelopes before any expensive decryption.
731
- if (this.seenEventIds.has(event.id)) {
732
- this.logger.debug('Skipping duplicate gift-wrapped event', {
733
- eventId: event.id,
734
- });
735
- return;
736
- }
737
- this.seenEventIds.set(event.id, true);
738
- await this.handleEncryptedEvent(event);
739
- }
740
- else {
741
- await this.handleUnencryptedEvent(event);
742
- }
743
- }
744
- catch (error) {
745
- this.logger.error('Error in processIncomingEvent', {
746
- error: error instanceof Error ? error.message : String(error),
747
- stack: error instanceof Error ? error.stack : undefined,
748
- eventId: event.id,
749
- eventKind: event.kind,
750
- });
751
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error instanceof Error ? error : new Error(String(error)));
752
- }
753
- }
754
- /**
755
- * Handles encrypted (gift-wrapped) events.
756
- * @param event The incoming gift-wrapped Nostr event.
757
- */
758
- async handleEncryptedEvent(event) {
759
- var _a;
760
- if (this.encryptionMode === EncryptionMode.DISABLED) {
761
- this.logger.error(`Received encrypted message from ${event.pubkey} but encryption is disabled. Ignoring.`);
762
- return;
763
- }
764
- try {
765
- const decryptedJson = await withTimeout(decryptMessage(event, this.signer), DEFAULT_TIMEOUT_MS, 'Decrypt message timed out');
766
- const currentEvent = JSON.parse(decryptedJson);
767
- // Verify the inner event's cryptographic signature to prevent identity
768
- // forgery. Without this check an attacker can place any pubkey inside
769
- // the plaintext and bypass allowlists. (Fixes #64)
770
- if (!verifyEvent(currentEvent)) {
771
- this.logger.error('Rejecting decrypted inner event with invalid signature', {
772
- innerEventId: currentEvent.id,
773
- innerPubkey: currentEvent.pubkey,
774
- outerEventId: event.id,
775
- });
776
- return;
777
- }
778
- // Deduplicate decrypted inner events before authorization and dispatch.
779
- if (this.seenEventIds.has(currentEvent.id)) {
780
- this.logger.debug('Skipping duplicate decrypted inner event', {
781
- outerEventId: event.id,
782
- innerEventId: currentEvent.id,
783
- });
784
- return;
785
- }
786
- this.seenEventIds.set(currentEvent.id, true);
787
- await this.authorizeAndProcessEvent(currentEvent, true, event.kind);
788
- }
789
- catch (error) {
790
- this.logger.error('Failed to handle encrypted Nostr event', {
791
- error: error instanceof Error ? error.message : String(error),
792
- stack: error instanceof Error ? error.stack : undefined,
793
- eventId: event.id,
794
- pubkey: event.pubkey,
795
- });
796
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error instanceof Error
797
- ? error
798
- : new Error('Failed to handle encrypted Nostr event'));
799
- }
800
- }
801
- /**
802
- * Handles unencrypted events.
803
- * @param event The incoming Nostr event.
804
- */
805
- async handleUnencryptedEvent(event) {
806
- if (this.encryptionMode === EncryptionMode.REQUIRED) {
807
- this.logger.error(`Received unencrypted message from ${event.pubkey} but encryption is required. Ignoring.`);
808
- return;
809
- }
810
- if (!verifyEvent(event)) {
811
- this.logger.error('Rejecting unencrypted event with invalid signature', {
812
- eventId: event.id,
813
- pubkey: event.pubkey,
814
- });
815
- return;
816
- }
817
- await this.authorizeAndProcessEvent(event, false);
818
- }
819
- /**
820
- * Authorizes and processes an incoming Nostr event, handling message validation,
821
- * client authorization, session management, and optional client public key injection.
822
- * @param event The Nostr event to process.
823
- * @param isEncrypted Whether the original event was encrypted.
824
- */
825
- async authorizeAndProcessEvent(event, isEncrypted, wrapKind) {
826
- var _a, _b, _c, _d, _e, _f, _g, _h;
827
- try {
828
- const mcpMessage = this.convertNostrEventToMcpMessage(event);
449
+ const unwrapped = await this.eventPipeline.unwrap(event);
450
+ if (unwrapped) {
451
+ const mcpMessage = this.convertNostrEventToMcpMessage(unwrapped.event);
829
452
  if (!mcpMessage) {
830
453
  this.logger.error('Skipping invalid Nostr event with malformed JSON content', {
831
- eventId: event.id,
832
- pubkey: event.pubkey,
833
- content: event.content,
454
+ eventId: unwrapped.event.id,
455
+ pubkey: unwrapped.event.pubkey,
456
+ content: unwrapped.event.content,
834
457
  });
835
458
  return;
836
459
  }
837
- const inboundMessage = mcpMessage;
838
- // Check authorization using the authorization policy
839
- const authDecision = await this.authorizationPolicy.authorize(event.pubkey, mcpMessage);
840
- if (!authDecision.allowed) {
841
- this.logger.error(`Unauthorized message from ${event.pubkey}, message: ${JSON.stringify(mcpMessage)}. Ignoring.`);
842
- if ('shouldReplyUnauthorized' in authDecision &&
843
- authDecision.shouldReplyUnauthorized &&
844
- isJSONRPCRequest(mcpMessage)) {
845
- const errorResponse = {
846
- jsonrpc: '2.0',
847
- id: mcpMessage.id,
848
- error: {
849
- code: -32000,
850
- message: 'Unauthorized',
851
- },
852
- };
853
- const tags = this.createResponseTags(event.pubkey, event.id);
854
- this.sendMcpMessage(errorResponse, event.pubkey, CTXVM_MESSAGES_KIND, tags, isEncrypted, undefined, isEncrypted
855
- ? this.giftWrapMode === GiftWrapMode.EPHEMERAL
856
- ? EPHEMERAL_GIFT_WRAP_KIND
857
- : this.giftWrapMode === GiftWrapMode.PERSISTENT
858
- ? GIFT_WRAP_KIND
859
- : wrapKind
860
- : undefined).catch((err) => {
861
- var _a;
862
- this.logger.error('Failed to send unauthorized response', {
863
- error: err instanceof Error ? err.message : String(err),
864
- pubkey: event.pubkey,
865
- eventId: event.id,
866
- });
867
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, new Error(`Failed to send unauthorized response: ${err}`));
868
- });
869
- }
870
- return;
871
- }
872
- const session = this.getOrCreateClientSession(event.pubkey, isEncrypted);
873
- const hadLearnedOversizedSupport = session.supportsOversizedTransfer;
874
- const discoveredCapabilities = learnPeerCapabilities(event.tags);
875
- session.supportsEncryption || (session.supportsEncryption = discoveredCapabilities.supportsEncryption);
876
- session.supportsEphemeralEncryption || (session.supportsEphemeralEncryption = discoveredCapabilities.supportsEphemeralEncryption);
877
- session.supportsOversizedTransfer || (session.supportsOversizedTransfer = this.oversizedEnabled &&
878
- discoveredCapabilities.supportsOversizedTransfer);
879
- session.supportsOpenStream || (session.supportsOpenStream = this.openStreamEnabled && discoveredCapabilities.supportsOpenStream);
880
- const shouldSendAccept = !hadLearnedOversizedSupport;
881
- const forward = async (msg) => {
882
- var _a, _b;
883
- (_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, msg);
884
- (_b = this.onmessageWithContext) === null || _b === void 0 ? void 0 : _b.call(this, msg, {
885
- clientPubkey: event.pubkey,
886
- });
887
- return true;
888
- };
889
- const clientPmis = event.tags
890
- .filter((tag) => tag[0] === 'pmi' && typeof tag[1] === 'string')
891
- .map((tag) => tag[1]);
892
- const ctx = {
893
- clientPubkey: event.pubkey,
894
- clientPmis: clientPmis.length > 0 ? clientPmis : undefined,
895
- };
896
- const middlewares = this.inboundMiddlewares;
897
- const dispatch = async (index, msg) => {
898
- const mw = middlewares[index];
899
- if (!mw) {
900
- return await forward(msg);
901
- }
902
- let forwarded = false;
903
- await mw(msg, ctx, async (nextMsg) => {
904
- forwarded = await dispatch(index + 1, nextMsg);
905
- });
906
- return forwarded;
907
- };
908
- if (isJSONRPCRequest(inboundMessage)) {
909
- this.handleIncomingRequest(event, event.id, inboundMessage, event.pubkey, wrapKind);
910
- if (this.shouldInjectRequestEventId) {
911
- injectRequestEventId(inboundMessage, event.id);
912
- }
913
- if (this.injectClientPubkey) {
914
- injectClientPubkey(inboundMessage, event.pubkey);
915
- }
916
- const openStreamWriter = this.openStreamWriters.get(event.id);
917
- if (openStreamWriter) {
918
- const params = (_a = inboundMessage.params) !== null && _a !== void 0 ? _a : {};
919
- inboundMessage.params = params;
920
- const meta = (_b = params._meta) !== null && _b !== void 0 ? _b : {};
921
- params._meta = meta;
922
- meta.stream = openStreamWriter;
923
- }
924
- }
925
- else if (isJSONRPCNotification(inboundMessage)) {
926
- this.handleIncomingNotification(event.pubkey, inboundMessage);
927
- if (inboundMessage.method === 'notifications/progress' &&
928
- OpenStreamReceiver.isOpenStreamFrame(inboundMessage)) {
929
- const frame = (_c = inboundMessage.params) === null || _c === void 0 ? void 0 : _c.cvm;
930
- if ((frame === null || frame === void 0 ? void 0 : frame.frameType) === 'abort') {
931
- const progressToken = String((_e = (_d = inboundMessage.params) === null || _d === void 0 ? void 0 : _d.progressToken) !== null && _e !== void 0 ? _e : '');
932
- const eventId = this.correlationStore.getEventIdByProgressToken(event.pubkey, progressToken);
933
- const writer = eventId
934
- ? this.openStreamWriters.get(eventId)
935
- : undefined;
936
- if (writer) {
937
- void writer.abort(frame.reason).catch((err) => {
938
- var _a;
939
- this.logger.error('Open stream abort propagation failed (server)', {
940
- error: err instanceof Error ? err.message : String(err),
941
- pubkey: event.pubkey,
942
- progressToken,
943
- });
944
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
945
- });
946
- }
947
- return;
948
- }
949
- if ((frame === null || frame === void 0 ? void 0 : frame.frameType) === 'ping') {
950
- const progressToken = String((_g = (_f = inboundMessage.params) === null || _f === void 0 ? void 0 : _f.progressToken) !== null && _g !== void 0 ? _g : '');
951
- const nonce = 'nonce' in frame && typeof frame.nonce === 'string'
952
- ? frame.nonce
953
- : '';
954
- const eventId = this.correlationStore.getEventIdByProgressToken(event.pubkey, progressToken);
955
- const writer = eventId
956
- ? this.openStreamWriters.get(eventId)
957
- : undefined;
958
- if (writer) {
959
- void writer.pong(nonce).catch((err) => {
960
- var _a;
961
- this.logger.error('Open stream ping handling failed (server)', {
962
- error: err instanceof Error ? err.message : String(err),
963
- pubkey: event.pubkey,
964
- progressToken,
965
- });
966
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
967
- });
968
- return;
969
- }
970
- }
971
- this.openStreamReceiver
972
- .processFrame(inboundMessage)
973
- .then(async () => {
974
- var _a, _b, _c, _d;
975
- const frameType = frame === null || frame === void 0 ? void 0 : frame.frameType;
976
- if (frameType === 'start' && session.supportsOpenStream) {
977
- await this.sendNotification(event.pubkey, {
978
- jsonrpc: '2.0',
979
- method: 'notifications/progress',
980
- params: buildOpenStreamAcceptFrame({
981
- progressToken: String((_b = (_a = inboundMessage.params) === null || _a === void 0 ? void 0 : _a.progressToken) !== null && _b !== void 0 ? _b : ''),
982
- progress: Number((_d = (_c = inboundMessage.params) === null || _c === void 0 ? void 0 : _c.progress) !== null && _d !== void 0 ? _d : 0) + 1,
983
- }),
984
- });
985
- }
986
- })
987
- .catch((err) => {
988
- var _a;
989
- this.logger.error('Open stream error (server)', {
990
- error: err instanceof Error ? err.message : String(err),
991
- pubkey: event.pubkey,
992
- });
993
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
994
- });
995
- return;
996
- }
997
- if (inboundMessage.method === 'notifications/progress' &&
998
- OversizedTransferReceiver.isOversizedFrame(inboundMessage)) {
999
- this.oversizedReceiver
1000
- .processFrame(inboundMessage)
1001
- .then(async (synthetic) => {
1002
- var _a, _b, _c, _d;
1003
- if (synthetic === null) {
1004
- if (((_b = (_a = inboundMessage.params) === null || _a === void 0 ? void 0 : _a.cvm) === null || _b === void 0 ? void 0 : _b.frameType) === 'start' &&
1005
- shouldSendAccept) {
1006
- await sendAcceptFrame({
1007
- clientPubkey: event.pubkey,
1008
- progressToken: String((_d = (_c = inboundMessage.params) === null || _c === void 0 ? void 0 : _c.progressToken) !== null && _d !== void 0 ? _d : ''),
1009
- }, {
1010
- sendNotification: this.sendNotification.bind(this),
1011
- }).catch((err) => {
1012
- this.logger.error('Failed to send oversized accept', {
1013
- error: err instanceof Error ? err.message : String(err),
1014
- });
1015
- });
1016
- }
1017
- return;
1018
- }
1019
- if (isJSONRPCRequest(synthetic)) {
1020
- this.handleIncomingRequest(event, event.id, synthetic, event.pubkey, wrapKind);
1021
- if (this.shouldInjectRequestEventId) {
1022
- injectRequestEventId(synthetic, event.id);
1023
- }
1024
- if (this.injectClientPubkey) {
1025
- injectClientPubkey(synthetic, event.pubkey);
1026
- }
1027
- }
1028
- else if (isJSONRPCNotification(synthetic)) {
1029
- this.handleIncomingNotification(event.pubkey, synthetic);
1030
- }
1031
- void dispatch(0, synthetic)
1032
- .then((forwarded) => {
1033
- if (!forwarded) {
1034
- this.cleanupDroppedRequest(synthetic);
1035
- }
1036
- })
1037
- .catch((err) => {
1038
- var _a;
1039
- this.logger.error('Error dispatching reassembled oversized message', {
1040
- error: err instanceof Error ? err.message : String(err),
1041
- pubkey: event.pubkey,
1042
- });
1043
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error
1044
- ? err
1045
- : new Error('oversized dispatch failed'));
1046
- });
1047
- })
1048
- .catch((err) => {
1049
- var _a;
1050
- this.logger.error('Oversized transfer error (server)', {
1051
- error: err instanceof Error ? err.message : String(err),
1052
- });
1053
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
1054
- });
1055
- return;
1056
- }
1057
- }
1058
- void dispatch(0, inboundMessage)
1059
- .then((forwarded) => {
1060
- if (!forwarded) {
1061
- this.cleanupDroppedRequest(inboundMessage);
1062
- }
1063
- })
1064
- .catch((err) => {
1065
- var _a;
1066
- this.logger.error('Error in inboundMiddleware chain', {
1067
- error: err instanceof Error ? err.message : String(err),
1068
- eventId: event.id,
1069
- pubkey: event.pubkey,
1070
- });
1071
- (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error('inboundMiddleware failed'));
1072
- });
1073
- }
1074
- catch (error) {
1075
- this.logger.error('Error in authorizeAndProcessEvent', {
1076
- error: error instanceof Error ? error.message : String(error),
1077
- stack: error instanceof Error ? error.stack : undefined,
1078
- eventId: event.id,
1079
- pubkey: event.pubkey,
1080
- });
1081
- (_h = this.onerror) === null || _h === void 0 ? void 0 : _h.call(this, error instanceof Error ? error : new Error(String(error)));
460
+ await this.inboundCoordinator.authorizeAndProcessEvent(unwrapped.event, unwrapped.isEncrypted, mcpMessage, unwrapped.wrapKind);
1082
461
  }
1083
462
  }
1084
463
  /**
@@ -1090,10 +469,11 @@ export class NostrServerTransport extends BaseNostrTransport {
1090
469
  sessionStore: this.sessionStore,
1091
470
  correlationStore: this.correlationStore,
1092
471
  oversizedReceiver: this.oversizedReceiver,
1093
- openStreamReceiver: this.openStreamReceiver,
1094
- pendingOpenStreamResponses: this.pendingOpenStreamResponses,
1095
- pendingOpenStreamSessionEvictions: this.pendingOpenStreamSessionEvictions,
1096
- openStreamWriters: this.openStreamWriters,
472
+ openStreamReceiver: this.openStreamFactory.getReceiver(),
473
+ openStreamWriters: this.openStreamFactory.getWritersMap(),
474
+ pendingOpenStreamResponses: this.openStreamFactory.getPendingResponsesMap(),
475
+ openStreamFactory: this.openStreamFactory,
476
+ inboundCoordinator: this.inboundCoordinator,
1097
477
  };
1098
478
  }
1099
479
  }