@contextvm/sdk 0.11.8 → 0.11.10
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/esm/core/utils/base64.d.ts +3 -0
- package/dist/esm/core/utils/base64.d.ts.map +1 -0
- package/dist/esm/core/utils/base64.js +24 -0
- package/dist/esm/core/utils/base64.js.map +1 -0
- package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.d.ts.map +1 -1
- package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.js +2 -1
- package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.js.map +1 -1
- package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.d.ts.map +1 -1
- package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.js +2 -1
- package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.js.map +1 -1
- package/dist/esm/transport/capability-negotiator.d.ts +141 -0
- package/dist/esm/transport/capability-negotiator.d.ts.map +1 -0
- package/dist/esm/transport/capability-negotiator.js +198 -0
- package/dist/esm/transport/capability-negotiator.js.map +1 -0
- package/dist/esm/transport/middleware.d.ts +9 -0
- package/dist/esm/transport/middleware.d.ts.map +1 -0
- package/dist/esm/transport/middleware.js +2 -0
- package/dist/esm/transport/middleware.js.map +1 -0
- package/dist/esm/transport/nostr-client/event-pipeline.d.ts +29 -0
- package/dist/esm/transport/nostr-client/event-pipeline.d.ts.map +1 -0
- package/dist/esm/transport/nostr-client/event-pipeline.js +109 -0
- package/dist/esm/transport/nostr-client/event-pipeline.js.map +1 -0
- package/dist/esm/transport/nostr-client/inbound-coordinator.d.ts +37 -0
- package/dist/esm/transport/nostr-client/inbound-coordinator.d.ts.map +1 -0
- package/dist/esm/transport/nostr-client/inbound-coordinator.js +159 -0
- package/dist/esm/transport/nostr-client/inbound-coordinator.js.map +1 -0
- package/dist/esm/transport/nostr-client/inbound-notification-dispatcher.d.ts +28 -0
- package/dist/esm/transport/nostr-client/inbound-notification-dispatcher.d.ts.map +1 -0
- package/dist/esm/transport/nostr-client/inbound-notification-dispatcher.js +65 -0
- package/dist/esm/transport/nostr-client/inbound-notification-dispatcher.js.map +1 -0
- package/dist/esm/transport/nostr-client/open-stream-factory.d.ts +36 -0
- package/dist/esm/transport/nostr-client/open-stream-factory.d.ts.map +1 -0
- package/dist/esm/transport/nostr-client/open-stream-factory.js +126 -0
- package/dist/esm/transport/nostr-client/open-stream-factory.js.map +1 -0
- package/dist/esm/transport/nostr-client/outbound-sender.d.ts +45 -0
- package/dist/esm/transport/nostr-client/outbound-sender.d.ts.map +1 -0
- package/dist/esm/transport/nostr-client/outbound-sender.js +105 -0
- package/dist/esm/transport/nostr-client/outbound-sender.js.map +1 -0
- package/dist/esm/transport/nostr-client/server-metadata-store.d.ts +35 -0
- package/dist/esm/transport/nostr-client/server-metadata-store.d.ts.map +1 -0
- package/dist/esm/transport/nostr-client/server-metadata-store.js +107 -0
- package/dist/esm/transport/nostr-client/server-metadata-store.js.map +1 -0
- package/dist/esm/transport/nostr-client-transport.d.ts +18 -41
- package/dist/esm/transport/nostr-client-transport.d.ts.map +1 -1
- package/dist/esm/transport/nostr-client-transport.js +117 -553
- package/dist/esm/transport/nostr-client-transport.js.map +1 -1
- package/dist/esm/transport/nostr-server/correlation-store.d.ts +2 -2
- package/dist/esm/transport/nostr-server/correlation-store.d.ts.map +1 -1
- package/dist/esm/transport/nostr-server/correlation-store.js +12 -3
- package/dist/esm/transport/nostr-server/correlation-store.js.map +1 -1
- package/dist/esm/transport/nostr-server/event-pipeline.d.ts +32 -0
- package/dist/esm/transport/nostr-server/event-pipeline.d.ts.map +1 -0
- package/dist/esm/transport/nostr-server/event-pipeline.js +118 -0
- package/dist/esm/transport/nostr-server/event-pipeline.js.map +1 -0
- package/dist/esm/transport/nostr-server/inbound-coordinator.d.ts +56 -0
- package/dist/esm/transport/nostr-server/inbound-coordinator.d.ts.map +1 -0
- package/dist/esm/transport/nostr-server/inbound-coordinator.js +168 -0
- package/dist/esm/transport/nostr-server/inbound-coordinator.js.map +1 -0
- package/dist/esm/transport/nostr-server/inbound-notification-dispatcher.d.ts +44 -0
- package/dist/esm/transport/nostr-server/inbound-notification-dispatcher.d.ts.map +1 -0
- package/dist/esm/transport/nostr-server/inbound-notification-dispatcher.js +153 -0
- package/dist/esm/transport/nostr-server/inbound-notification-dispatcher.js.map +1 -0
- package/dist/esm/transport/nostr-server/open-stream-factory.d.ts +81 -0
- package/dist/esm/transport/nostr-server/open-stream-factory.d.ts.map +1 -0
- package/dist/esm/transport/nostr-server/open-stream-factory.js +224 -0
- package/dist/esm/transport/nostr-server/open-stream-factory.js.map +1 -0
- package/dist/esm/transport/nostr-server/outbound-notification-broadcaster.d.ts +24 -0
- package/dist/esm/transport/nostr-server/outbound-notification-broadcaster.d.ts.map +1 -0
- package/dist/esm/transport/nostr-server/outbound-notification-broadcaster.js +64 -0
- package/dist/esm/transport/nostr-server/outbound-notification-broadcaster.js.map +1 -0
- package/dist/esm/transport/nostr-server/outbound-response-router.d.ts +62 -0
- package/dist/esm/transport/nostr-server/outbound-response-router.d.ts.map +1 -0
- package/dist/esm/transport/nostr-server/outbound-response-router.js +125 -0
- package/dist/esm/transport/nostr-server/outbound-response-router.js.map +1 -0
- package/dist/esm/transport/nostr-server-transport.d.ts +15 -62
- package/dist/esm/transport/nostr-server-transport.d.ts.map +1 -1
- package/dist/esm/transport/nostr-server-transport.js +121 -741
- package/dist/esm/transport/nostr-server-transport.js.map +1 -1
- package/dist/esm/transport/open-stream/registry.d.ts.map +1 -1
- package/dist/esm/transport/open-stream/registry.js +7 -1
- package/dist/esm/transport/open-stream/registry.js.map +1 -1
- package/dist/esm/transport/open-stream/session.d.ts +1 -0
- package/dist/esm/transport/open-stream/session.d.ts.map +1 -1
- package/dist/esm/transport/open-stream/session.js +14 -4
- package/dist/esm/transport/open-stream/session.js.map +1 -1
- package/dist/esm/transport/server-transport-common-schemas.d.ts +1 -0
- package/dist/esm/transport/server-transport-common-schemas.d.ts.map +1 -1
- package/dist/esm/transport/server-transport-common-schemas.js +21 -1
- package/dist/esm/transport/server-transport-common-schemas.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,21 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { NotificationSchema, isJSONRPCRequest, isJSONRPCNotification, } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { DEFAULT_BOOTSTRAP_RELAY_URLS, DEFAULT_TIMEOUT_MS, DEFAULT_LRU_SIZE, INITIALIZE_METHOD, } from '../core/index.js';
|
|
3
3
|
import { LruCache } from '../core/utils/lru-cache.js';
|
|
4
4
|
import { BaseNostrTransport, } from './base-nostr-transport.js';
|
|
5
|
-
import { getNostrEventTag } from '../core/utils/serializers.js';
|
|
6
|
-
import { verifyEvent } from 'nostr-tools/pure';
|
|
7
|
-
import { EncryptionMode, GiftWrapMode } from '../core/interfaces.js';
|
|
8
5
|
import { ClientCorrelationStore, } from './nostr-client/correlation-store.js';
|
|
9
6
|
import { parseServerIdentity } from './nostr-client/server-identity.js';
|
|
10
7
|
import { resolveOperationalRelays } from './nostr-client/relay-resolution.js';
|
|
11
8
|
import { StatelessModeHandler } from './nostr-client/stateless-mode-handler.js';
|
|
12
|
-
import { queryTags, withTimeout } from '../core/utils/utils.js';
|
|
13
9
|
import { OversizedTransferReceiver, } from './oversized-transfer/index.js';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
10
|
+
import { ClientCapabilityNegotiator } from './capability-negotiator.js';
|
|
11
|
+
import { ClientInboundCoordinator } from './nostr-client/inbound-coordinator.js';
|
|
12
|
+
import { ServerMetadataStore } from './nostr-client/server-metadata-store.js';
|
|
13
|
+
import { ClientOutboundSender } from './nostr-client/outbound-sender.js';
|
|
14
|
+
import { ClientInboundNotificationDispatcher } from './nostr-client/inbound-notification-dispatcher.js';
|
|
15
|
+
import { ClientEventPipeline } from './nostr-client/event-pipeline.js';
|
|
16
|
+
import { ClientOpenStreamFactory } from './nostr-client/open-stream-factory.js';
|
|
17
17
|
import { DEFAULT_CHUNK_SIZE, DEFAULT_OVERSIZED_THRESHOLD, } from './oversized-transfer/constants.js';
|
|
18
|
-
import { sendOversizedClientRequest } from './nostr-client/oversized-client-sender.js';
|
|
19
18
|
/**
|
|
20
19
|
* A client transport layer for CTXVM that uses Nostr events for communication.
|
|
21
20
|
* Implements the Transport interface from the @modelcontextprotocol/sdk.
|
|
@@ -28,21 +27,13 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
28
27
|
* @throws Error if serverPubkey is not a valid supported server identifier
|
|
29
28
|
*/
|
|
30
29
|
constructor(options) {
|
|
31
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m
|
|
30
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
32
31
|
super('nostr-client-transport', {
|
|
33
32
|
...options,
|
|
34
33
|
relayHandler: (_a = options.relayHandler) !== null && _a !== void 0 ? _a : [],
|
|
35
34
|
});
|
|
36
35
|
this.pendingOutboundOpenStreamResolvers = [];
|
|
37
36
|
this.onmessageWithContext = undefined;
|
|
38
|
-
/** Whether the server has advertised ephemeral gift wrap support via Nostr tags. */
|
|
39
|
-
this.serverSupportsEphemeralGiftWraps = false;
|
|
40
|
-
/** Whether the server has advertised CEP-22 oversized transfer support. */
|
|
41
|
-
this.serverSupportsOversizedTransfer = false;
|
|
42
|
-
/** Whether the server has advertised CEP-41 open stream support. */
|
|
43
|
-
this.serverSupportsOpenStream = false;
|
|
44
|
-
/** Whether this client has already sent its discovery tags to the server. */
|
|
45
|
-
this.hasSentDiscoveryTags = false;
|
|
46
37
|
/**
|
|
47
38
|
* Deduplicate inbound events to avoid redundant work.
|
|
48
39
|
*
|
|
@@ -64,6 +55,7 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
64
55
|
},
|
|
65
56
|
});
|
|
66
57
|
this.statelessHandler = new StatelessModeHandler();
|
|
58
|
+
this.metadataStore = new ServerMetadataStore();
|
|
67
59
|
const ot = options.oversizedTransfer;
|
|
68
60
|
this.oversizedEnabled = (_e = ot === null || ot === void 0 ? void 0 : ot.enabled) !== null && _e !== void 0 ? _e : true;
|
|
69
61
|
this.oversizedThreshold = (_f = ot === null || ot === void 0 ? void 0 : ot.thresholdBytes) !== null && _f !== void 0 ? _f : DEFAULT_OVERSIZED_THRESHOLD;
|
|
@@ -71,55 +63,65 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
71
63
|
this.oversizedAcceptTimeoutMs = (_h = ot === null || ot === void 0 ? void 0 : ot.acceptTimeoutMs) !== null && _h !== void 0 ? _h : DEFAULT_TIMEOUT_MS;
|
|
72
64
|
this.oversizedReceiver = new OversizedTransferReceiver((_j = ot === null || ot === void 0 ? void 0 : ot.policy) !== null && _j !== void 0 ? _j : {}, this.logger);
|
|
73
65
|
this.openStreamEnabled = (_l = (_k = options.openStream) === null || _k === void 0 ? void 0 : _k.enabled) !== null && _l !== void 0 ? _l : false;
|
|
74
|
-
this.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
66
|
+
this.openStreamFactory = new ClientOpenStreamFactory({
|
|
67
|
+
openStreamEnabled: this.openStreamEnabled,
|
|
68
|
+
policy: (_m = options.openStream) === null || _m === void 0 ? void 0 : _m.policy,
|
|
69
|
+
send: this.send.bind(this),
|
|
70
|
+
logger: this.logger,
|
|
71
|
+
onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
|
|
72
|
+
});
|
|
73
|
+
this.capabilityNegotiator = new ClientCapabilityNegotiator({
|
|
74
|
+
encryptionMode: this.encryptionMode,
|
|
75
|
+
giftWrapMode: this.giftWrapMode,
|
|
76
|
+
oversizedEnabled: this.oversizedEnabled,
|
|
77
|
+
openStreamEnabled: this.openStreamEnabled,
|
|
78
|
+
composeOutboundTags: this.composeOutboundTags.bind(this),
|
|
79
|
+
});
|
|
80
|
+
this.inboundNotificationDispatcher =
|
|
81
|
+
new ClientInboundNotificationDispatcher({
|
|
82
|
+
openStreamReceiver: this.openStreamFactory.getReceiver(),
|
|
83
|
+
oversizedReceiver: this.oversizedReceiver,
|
|
84
|
+
handleResponse: this.handleResponse.bind(this),
|
|
85
|
+
handleNotification: this.handleNotification.bind(this),
|
|
86
|
+
logger: this.logger,
|
|
87
|
+
onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
|
|
88
|
+
});
|
|
89
|
+
this.eventPipeline = new ClientEventPipeline({
|
|
90
|
+
signer: this.signer,
|
|
91
|
+
seenEventIds: this.seenEventIds,
|
|
92
|
+
serverPubkey: this.serverPubkey,
|
|
93
|
+
giftWrapMode: this.giftWrapMode,
|
|
94
|
+
logger: this.logger,
|
|
95
|
+
onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
|
|
96
|
+
});
|
|
97
|
+
this.inboundCoordinator = new ClientInboundCoordinator({
|
|
98
|
+
capabilityNegotiator: this.capabilityNegotiator,
|
|
99
|
+
correlationStore: this.correlationStore,
|
|
100
|
+
notificationDispatcher: this.inboundNotificationDispatcher,
|
|
101
|
+
metadataStore: this.metadataStore,
|
|
102
|
+
unwrapEvent: this.eventPipeline.unwrap.bind(this.eventPipeline),
|
|
103
|
+
convertNostrEventToMcpMessage: this.convertNostrEventToMcpMessage.bind(this),
|
|
104
|
+
handleResponse: this.handleResponse.bind(this),
|
|
105
|
+
handleNotification: this.handleNotification.bind(this),
|
|
106
|
+
logger: this.logger,
|
|
107
|
+
onerror: (error) => { var _a; return (_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error); },
|
|
108
|
+
});
|
|
109
|
+
this.outboundSender = new ClientOutboundSender({
|
|
110
|
+
serverPubkey: this.serverPubkey,
|
|
111
|
+
correlationStore: this.correlationStore,
|
|
112
|
+
capabilityNegotiator: this.capabilityNegotiator,
|
|
113
|
+
oversizedEnabled: this.oversizedEnabled,
|
|
114
|
+
oversizedThreshold: this.oversizedThreshold,
|
|
115
|
+
oversizedChunkSize: this.oversizedChunkSize,
|
|
116
|
+
oversizedAcceptTimeoutMs: this.oversizedAcceptTimeoutMs,
|
|
117
|
+
serverSupportsOversizedTransfer: () => this.metadataStore.getServerSupportsOversizedTransfer(),
|
|
118
|
+
createRecipientTags: this.createRecipientTags.bind(this),
|
|
119
|
+
sendMcpMessage: this.sendMcpMessage.bind(this),
|
|
120
|
+
waitForAccept: this.oversizedReceiver.waitForAccept.bind(this.oversizedReceiver),
|
|
121
|
+
getOriginalRequestContext: this.getOriginalRequestContext.bind(this),
|
|
122
|
+
resolvePendingOpenStream: this.resolvePendingOutboundOpenStream.bind(this),
|
|
123
|
+
measurePublishedMcpMessageSize: this.measurePublishedMcpMessageSize.bind(this),
|
|
124
|
+
resolveSafeOversizedChunkSize: this.resolveSafeOversizedChunkSize.bind(this),
|
|
123
125
|
logger: this.logger,
|
|
124
126
|
});
|
|
125
127
|
}
|
|
@@ -129,49 +131,7 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
129
131
|
* Intended to be called by payments wrappers (e.g. `withClientPayments()`).
|
|
130
132
|
*/
|
|
131
133
|
setClientPmis(pmis) {
|
|
132
|
-
this.
|
|
133
|
-
}
|
|
134
|
-
getClientCapabilityTags() {
|
|
135
|
-
const tags = [];
|
|
136
|
-
if (this.encryptionMode !== EncryptionMode.DISABLED) {
|
|
137
|
-
tags.push([NOSTR_TAGS.SUPPORT_ENCRYPTION]);
|
|
138
|
-
}
|
|
139
|
-
if (this.encryptionMode !== EncryptionMode.DISABLED &&
|
|
140
|
-
this.giftWrapMode !== GiftWrapMode.PERSISTENT) {
|
|
141
|
-
tags.push([NOSTR_TAGS.SUPPORT_ENCRYPTION_EPHEMERAL]);
|
|
142
|
-
}
|
|
143
|
-
if (this.oversizedEnabled) {
|
|
144
|
-
tags.push([NOSTR_TAGS.SUPPORT_OVERSIZED_TRANSFER]);
|
|
145
|
-
}
|
|
146
|
-
if (this.openStreamEnabled) {
|
|
147
|
-
tags.push([NOSTR_TAGS.SUPPORT_OPEN_STREAM]);
|
|
148
|
-
}
|
|
149
|
-
return tags;
|
|
150
|
-
}
|
|
151
|
-
getClientNegotiationTags() {
|
|
152
|
-
const tags = [];
|
|
153
|
-
if (this.clientPmis) {
|
|
154
|
-
tags.push(...this.clientPmis.map((pmi) => ['pmi', pmi]));
|
|
155
|
-
}
|
|
156
|
-
return tags;
|
|
157
|
-
}
|
|
158
|
-
getPendingClientDiscoveryTags() {
|
|
159
|
-
return this.hasSentDiscoveryTags ? [] : this.getClientCapabilityTags();
|
|
160
|
-
}
|
|
161
|
-
buildOutboundClientTags(params) {
|
|
162
|
-
const { baseTags, includeDiscovery } = params;
|
|
163
|
-
return this.composeOutboundTags({
|
|
164
|
-
baseTags,
|
|
165
|
-
discoveryTags: includeDiscovery
|
|
166
|
-
? this.getPendingClientDiscoveryTags()
|
|
167
|
-
: [],
|
|
168
|
-
negotiationTags: includeDiscovery ? this.getClientNegotiationTags() : [],
|
|
169
|
-
});
|
|
170
|
-
}
|
|
171
|
-
markClientDiscoveryTagsSent() {
|
|
172
|
-
if (this.getPendingClientDiscoveryTags().length > 0) {
|
|
173
|
-
this.hasSentDiscoveryTags = true;
|
|
174
|
-
}
|
|
134
|
+
this.capabilityNegotiator.setClientPmis(pmis);
|
|
175
135
|
}
|
|
176
136
|
/**
|
|
177
137
|
* Starts the transport, connecting to the relay and setting up event listeners.
|
|
@@ -221,9 +181,10 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
221
181
|
pending.reject(pendingOpenStreamError);
|
|
222
182
|
}
|
|
223
183
|
this.correlationStore.clear();
|
|
184
|
+
this.metadataStore.clear();
|
|
224
185
|
this.seenEventIds.clear();
|
|
225
186
|
this.oversizedReceiver.clear();
|
|
226
|
-
this.
|
|
187
|
+
this.openStreamFactory.getReceiver().clear();
|
|
227
188
|
(_a = this.onclose) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
228
189
|
}
|
|
229
190
|
catch (error) {
|
|
@@ -248,7 +209,7 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
248
209
|
}
|
|
249
210
|
return;
|
|
250
211
|
}
|
|
251
|
-
await this.sendRequest(message);
|
|
212
|
+
await this.outboundSender.sendRequest(message);
|
|
252
213
|
}
|
|
253
214
|
catch (error) {
|
|
254
215
|
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, error instanceof Error ? error : new Error(String(error)));
|
|
@@ -264,118 +225,6 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
264
225
|
});
|
|
265
226
|
}
|
|
266
227
|
}
|
|
267
|
-
/**
|
|
268
|
-
* Sends a request and registers it for correlation tracking.
|
|
269
|
-
* @param message - The JSON-RPC message to send
|
|
270
|
-
* @returns The ID of the published Nostr event
|
|
271
|
-
*/
|
|
272
|
-
async sendRequest(message) {
|
|
273
|
-
var _a, _b;
|
|
274
|
-
const isRequest = isJSONRPCRequest(message);
|
|
275
|
-
const tags = this.buildOutboundClientTags({
|
|
276
|
-
baseTags: this.createRecipientTags(this.serverPubkey),
|
|
277
|
-
includeDiscovery: isRequest,
|
|
278
|
-
});
|
|
279
|
-
const giftWrapKind = this.chooseOutboundGiftWrapKind();
|
|
280
|
-
// --- CEP-22 Oversized Transfer (proactive path) ---
|
|
281
|
-
if (this.oversizedEnabled && isRequest) {
|
|
282
|
-
const progressToken = (_b = (_a = message.params) === null || _a === void 0 ? void 0 : _a._meta) === null || _b === void 0 ? void 0 : _b.progressToken;
|
|
283
|
-
if (progressToken !== undefined) {
|
|
284
|
-
const serialized = JSON.stringify(message);
|
|
285
|
-
const publishedEventSize = await this.measurePublishedMcpMessageSize(message, this.serverPubkey, CTXVM_MESSAGES_KIND, tags, undefined, giftWrapKind);
|
|
286
|
-
if (publishedEventSize > this.oversizedThreshold) {
|
|
287
|
-
await this.sendOversizedRequest(message, serialized, String(progressToken), giftWrapKind);
|
|
288
|
-
return 'oversized-transfer';
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
const eventId = await this.sendMcpMessage(message, this.serverPubkey, CTXVM_MESSAGES_KIND, tags, undefined, (eventId) => {
|
|
293
|
-
var _a, _b;
|
|
294
|
-
const progressToken = isRequest
|
|
295
|
-
? (_b = (_a = message.params) === null || _a === void 0 ? void 0 : _a._meta) === null || _b === void 0 ? void 0 : _b.progressToken
|
|
296
|
-
: undefined;
|
|
297
|
-
const originalRequestContext = isRequest
|
|
298
|
-
? this.getOriginalRequestContext(message)
|
|
299
|
-
: undefined;
|
|
300
|
-
this.correlationStore.registerRequest(eventId, {
|
|
301
|
-
originalRequestId: isRequest ? message.id : null,
|
|
302
|
-
isInitialize: isRequest && message.method === INITIALIZE_METHOD,
|
|
303
|
-
progressToken: progressToken !== undefined ? String(progressToken) : undefined,
|
|
304
|
-
originalRequestContext,
|
|
305
|
-
});
|
|
306
|
-
if (isRequest &&
|
|
307
|
-
message.method === 'tools/call' &&
|
|
308
|
-
progressToken !== undefined) {
|
|
309
|
-
const pending = this.pendingOutboundOpenStreamResolvers.shift();
|
|
310
|
-
if (pending) {
|
|
311
|
-
const normalizedProgressToken = String(progressToken);
|
|
312
|
-
pending.resolve({
|
|
313
|
-
progressToken: normalizedProgressToken,
|
|
314
|
-
stream: this.createOutboundOpenStreamSession(normalizedProgressToken),
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}, giftWrapKind);
|
|
319
|
-
if (isRequest) {
|
|
320
|
-
this.markClientDiscoveryTagsSent();
|
|
321
|
-
}
|
|
322
|
-
return eventId;
|
|
323
|
-
}
|
|
324
|
-
//Splits an oversized request into CEP-22 transfer frames and sends them sequentially. Waits for an `accept` frame from the server when the server's support is not yet known.
|
|
325
|
-
async sendOversizedRequest(originalMessage, serialized, progressToken, giftWrapKind) {
|
|
326
|
-
const frameRecipientTags = this.createRecipientTags(this.serverPubkey);
|
|
327
|
-
const startFrameTags = this.buildOutboundClientTags({
|
|
328
|
-
baseTags: frameRecipientTags,
|
|
329
|
-
includeDiscovery: true,
|
|
330
|
-
});
|
|
331
|
-
const chunkSizeBytes = await this.resolveSafeOversizedChunkSize({
|
|
332
|
-
desiredChunkSizeBytes: this.oversizedChunkSize,
|
|
333
|
-
maxPublishedEventBytes: this.oversizedThreshold,
|
|
334
|
-
recipientPublicKey: this.serverPubkey,
|
|
335
|
-
kind: CTXVM_MESSAGES_KIND,
|
|
336
|
-
progressToken,
|
|
337
|
-
progress: this.serverSupportsOversizedTransfer ? 2 : 3,
|
|
338
|
-
tags: frameRecipientTags,
|
|
339
|
-
giftWrapKind,
|
|
340
|
-
});
|
|
341
|
-
const endFrameEventId = await sendOversizedClientRequest(serialized, progressToken, {
|
|
342
|
-
chunkSizeBytes,
|
|
343
|
-
acceptTimeoutMs: this.oversizedAcceptTimeoutMs,
|
|
344
|
-
serverPubkey: this.serverPubkey,
|
|
345
|
-
serverSupportsOversizedTransfer: this.serverSupportsOversizedTransfer,
|
|
346
|
-
giftWrapKind,
|
|
347
|
-
startFrameTags,
|
|
348
|
-
continuationFrameTags: frameRecipientTags,
|
|
349
|
-
}, {
|
|
350
|
-
sendMcpMessage: this.sendMcpMessage.bind(this),
|
|
351
|
-
waitForAccept: this.oversizedReceiver.waitForAccept.bind(this.oversizedReceiver),
|
|
352
|
-
logger: this.logger,
|
|
353
|
-
});
|
|
354
|
-
// Register the original request for correlating the final response.
|
|
355
|
-
if (endFrameEventId) {
|
|
356
|
-
this.correlationStore.registerRequest(endFrameEventId, {
|
|
357
|
-
originalRequestId: originalMessage.id,
|
|
358
|
-
isInitialize: originalMessage.method === INITIALIZE_METHOD,
|
|
359
|
-
progressToken,
|
|
360
|
-
originalRequestContext: this.getOriginalRequestContext(originalMessage),
|
|
361
|
-
});
|
|
362
|
-
}
|
|
363
|
-
this.markClientDiscoveryTagsSent();
|
|
364
|
-
}
|
|
365
|
-
chooseOutboundGiftWrapKind() {
|
|
366
|
-
// Strict modes are deterministic.
|
|
367
|
-
if (this.giftWrapMode === GiftWrapMode.PERSISTENT)
|
|
368
|
-
return GIFT_WRAP_KIND;
|
|
369
|
-
if (this.giftWrapMode === GiftWrapMode.EPHEMERAL)
|
|
370
|
-
return EPHEMERAL_GIFT_WRAP_KIND;
|
|
371
|
-
if (this.serverSupportsEphemeralGiftWraps) {
|
|
372
|
-
return EPHEMERAL_GIFT_WRAP_KIND;
|
|
373
|
-
}
|
|
374
|
-
const supportsEphemeralFromInit = queryTags(this.serverInitializeEvent, NOSTR_TAGS.SUPPORT_ENCRYPTION_EPHEMERAL).isFlag;
|
|
375
|
-
return supportsEphemeralFromInit
|
|
376
|
-
? EPHEMERAL_GIFT_WRAP_KIND
|
|
377
|
-
: GIFT_WRAP_KIND;
|
|
378
|
-
}
|
|
379
228
|
getOriginalRequestContext(message) {
|
|
380
229
|
var _a, _b, _c;
|
|
381
230
|
if (!isJSONRPCRequest(message))
|
|
@@ -419,63 +268,14 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
419
268
|
* Returns the CEP-41 stream session for a progress token, creating it lazily if needed.
|
|
420
269
|
*/
|
|
421
270
|
getOrCreateOpenStreamSession(progressToken) {
|
|
422
|
-
return this.
|
|
271
|
+
return this.openStreamFactory.getOrCreateSession(progressToken);
|
|
423
272
|
}
|
|
424
273
|
/**
|
|
425
274
|
* Returns an outbound CEP-41 session whose local abort publishes an abort
|
|
426
275
|
* notification to the server.
|
|
427
276
|
*/
|
|
428
277
|
createOutboundOpenStreamSession(progressToken) {
|
|
429
|
-
|
|
430
|
-
const existing = this.openStreamReceiver.getSession(progressToken);
|
|
431
|
-
if (existing) {
|
|
432
|
-
return existing;
|
|
433
|
-
}
|
|
434
|
-
let progress = 0;
|
|
435
|
-
return this.openStreamReceiver.createSession({
|
|
436
|
-
progressToken,
|
|
437
|
-
maxBufferedChunks: (_b = (_a = this.openStreamPolicy) === null || _a === void 0 ? void 0 : _a.maxBufferedChunksPerStream) !== null && _b !== void 0 ? _b : DEFAULT_MAX_BUFFERED_CHUNKS_PER_STREAM,
|
|
438
|
-
maxBufferedBytes: (_d = (_c = this.openStreamPolicy) === null || _c === void 0 ? void 0 : _c.maxBufferedBytesPerStream) !== null && _d !== void 0 ? _d : DEFAULT_MAX_BUFFERED_BYTES_PER_STREAM,
|
|
439
|
-
idleTimeoutMs: (_f = (_e = this.openStreamPolicy) === null || _e === void 0 ? void 0 : _e.idleTimeoutMs) !== null && _f !== void 0 ? _f : DEFAULT_OPEN_STREAM_IDLE_TIMEOUT_MS,
|
|
440
|
-
probeTimeoutMs: (_h = (_g = this.openStreamPolicy) === null || _g === void 0 ? void 0 : _g.probeTimeoutMs) !== null && _h !== void 0 ? _h : DEFAULT_OPEN_STREAM_PROBE_TIMEOUT_MS,
|
|
441
|
-
closeGracePeriodMs: (_k = (_j = this.openStreamPolicy) === null || _j === void 0 ? void 0 : _j.closeGracePeriodMs) !== null && _k !== void 0 ? _k : DEFAULT_OPEN_STREAM_CLOSE_GRACE_PERIOD_MS,
|
|
442
|
-
sendPing: async (nonce) => {
|
|
443
|
-
progress += 1;
|
|
444
|
-
await this.send({
|
|
445
|
-
jsonrpc: '2.0',
|
|
446
|
-
method: 'notifications/progress',
|
|
447
|
-
params: buildOpenStreamPingFrame({
|
|
448
|
-
progressToken,
|
|
449
|
-
progress,
|
|
450
|
-
nonce,
|
|
451
|
-
}),
|
|
452
|
-
});
|
|
453
|
-
},
|
|
454
|
-
sendPong: async (nonce) => {
|
|
455
|
-
progress += 1;
|
|
456
|
-
await this.send({
|
|
457
|
-
jsonrpc: '2.0',
|
|
458
|
-
method: 'notifications/progress',
|
|
459
|
-
params: buildOpenStreamPongFrame({
|
|
460
|
-
progressToken,
|
|
461
|
-
progress,
|
|
462
|
-
nonce,
|
|
463
|
-
}),
|
|
464
|
-
});
|
|
465
|
-
},
|
|
466
|
-
sendAbort: async (reason) => {
|
|
467
|
-
progress += 1;
|
|
468
|
-
await this.send({
|
|
469
|
-
jsonrpc: '2.0',
|
|
470
|
-
method: 'notifications/progress',
|
|
471
|
-
params: buildOpenStreamAbortFrame({
|
|
472
|
-
progressToken,
|
|
473
|
-
progress,
|
|
474
|
-
reason,
|
|
475
|
-
}),
|
|
476
|
-
});
|
|
477
|
-
},
|
|
478
|
-
});
|
|
278
|
+
return this.openStreamFactory.createOutboundSession(progressToken);
|
|
479
279
|
}
|
|
480
280
|
/**
|
|
481
281
|
* Resolves the next outbound CEP-41 session created from an SDK-generated progress token.
|
|
@@ -485,11 +285,22 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
485
285
|
this.pendingOutboundOpenStreamResolvers.push({ resolve, reject });
|
|
486
286
|
});
|
|
487
287
|
}
|
|
288
|
+
/** Resolves the next outbound open-stream placeholder with an active session. */
|
|
289
|
+
resolvePendingOutboundOpenStream(progressToken) {
|
|
290
|
+
const pending = this.pendingOutboundOpenStreamResolvers.shift();
|
|
291
|
+
if (!pending) {
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
pending.resolve({
|
|
295
|
+
progressToken,
|
|
296
|
+
stream: this.createOutboundOpenStreamSession(progressToken),
|
|
297
|
+
});
|
|
298
|
+
}
|
|
488
299
|
/**
|
|
489
300
|
* Returns the CEP-41 stream session for a progress token when it already exists.
|
|
490
301
|
*/
|
|
491
302
|
getOpenStreamSession(progressToken) {
|
|
492
|
-
return this.
|
|
303
|
+
return this.openStreamFactory.getSession(progressToken);
|
|
493
304
|
}
|
|
494
305
|
/**
|
|
495
306
|
* Emulates the server's initialize response for stateless clients.
|
|
@@ -517,281 +328,79 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
517
328
|
* @param event - The incoming Nostr event
|
|
518
329
|
*/
|
|
519
330
|
async processIncomingEvent(event) {
|
|
520
|
-
|
|
521
|
-
try {
|
|
522
|
-
let nostrEvent = event;
|
|
523
|
-
if (event.kind === GIFT_WRAP_KIND ||
|
|
524
|
-
event.kind === EPHEMERAL_GIFT_WRAP_KIND) {
|
|
525
|
-
if (!this.isGiftWrapKindAllowed(event.kind)) {
|
|
526
|
-
this.logger.debug('Skipping gift wrap due to GiftWrapMode policy', {
|
|
527
|
-
eventId: event.id,
|
|
528
|
-
kind: event.kind,
|
|
529
|
-
});
|
|
530
|
-
return;
|
|
531
|
-
}
|
|
532
|
-
// Deduplicate gift-wrap envelopes before any expensive decryption.
|
|
533
|
-
if (this.seenEventIds.has(event.id)) {
|
|
534
|
-
this.logger.debug('Skipping duplicate gift-wrapped event', {
|
|
535
|
-
eventId: event.id,
|
|
536
|
-
});
|
|
537
|
-
return;
|
|
538
|
-
}
|
|
539
|
-
this.seenEventIds.set(event.id, true);
|
|
540
|
-
try {
|
|
541
|
-
const decryptedContent = await withTimeout(decryptMessage(event, this.signer), DEFAULT_TIMEOUT_MS, 'Decrypt message timed out');
|
|
542
|
-
nostrEvent = JSON.parse(decryptedContent);
|
|
543
|
-
// Verify the inner event's cryptographic signature to prevent
|
|
544
|
-
// identity forgery. Without this check an attacker can place the
|
|
545
|
-
// server's pubkey inside the plaintext and spoof responses. (Fixes #64)
|
|
546
|
-
if (!verifyEvent(nostrEvent)) {
|
|
547
|
-
this.logger.error('Rejecting decrypted inner event with invalid signature', {
|
|
548
|
-
innerEventId: nostrEvent.id,
|
|
549
|
-
innerPubkey: nostrEvent.pubkey,
|
|
550
|
-
outerEventId: event.id,
|
|
551
|
-
});
|
|
552
|
-
return;
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
catch (decryptError) {
|
|
556
|
-
this.logger.error('Failed to decrypt gift-wrapped event', {
|
|
557
|
-
error: decryptError instanceof Error
|
|
558
|
-
? decryptError.message
|
|
559
|
-
: String(decryptError),
|
|
560
|
-
stack: decryptError instanceof Error ? decryptError.stack : undefined,
|
|
561
|
-
eventId: event.id,
|
|
562
|
-
pubkey: event.pubkey,
|
|
563
|
-
});
|
|
564
|
-
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, decryptError instanceof Error
|
|
565
|
-
? decryptError
|
|
566
|
-
: new Error('Failed to decrypt gift-wrapped event'));
|
|
567
|
-
return;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
if (nostrEvent.pubkey !== this.serverPubkey) {
|
|
571
|
-
this.logger.debug('Skipping event from unexpected server pubkey:', {
|
|
572
|
-
receivedPubkey: nostrEvent.pubkey,
|
|
573
|
-
expectedPubkey: this.serverPubkey,
|
|
574
|
-
eventId: nostrEvent.id,
|
|
575
|
-
});
|
|
576
|
-
return;
|
|
577
|
-
}
|
|
578
|
-
if (event.kind !== GIFT_WRAP_KIND &&
|
|
579
|
-
event.kind !== EPHEMERAL_GIFT_WRAP_KIND) {
|
|
580
|
-
if (!verifyEvent(nostrEvent)) {
|
|
581
|
-
this.logger.error('Rejecting unencrypted event with invalid signature', {
|
|
582
|
-
eventId: nostrEvent.id,
|
|
583
|
-
pubkey: nostrEvent.pubkey,
|
|
584
|
-
});
|
|
585
|
-
return;
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
this.learnServerDiscovery(nostrEvent);
|
|
589
|
-
const eTag = getNostrEventTag(nostrEvent.tags, 'e');
|
|
590
|
-
if (!this.serverInitializeEvent && eTag) {
|
|
591
|
-
try {
|
|
592
|
-
const content = JSON.parse(nostrEvent.content);
|
|
593
|
-
const parse = InitializeResultSchema.safeParse(content.result);
|
|
594
|
-
if (parse.success) {
|
|
595
|
-
this.serverInitializeEvent = nostrEvent;
|
|
596
|
-
this.logger.info('Received server initialize event', {
|
|
597
|
-
eventId: nostrEvent.id,
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
catch (_c) {
|
|
602
|
-
this.logger.debug('Event is not a valid initialize response', {
|
|
603
|
-
eventId: nostrEvent.id,
|
|
604
|
-
});
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
const mcpMessage = this.convertNostrEventToMcpMessage(nostrEvent);
|
|
608
|
-
if (!mcpMessage) {
|
|
609
|
-
this.logger.error('Skipping invalid Nostr event with malformed JSON content', { eventId: nostrEvent.id, pubkey: nostrEvent.pubkey });
|
|
610
|
-
return;
|
|
611
|
-
}
|
|
612
|
-
// Message classification MUST be based on JSON-RPC type, not on the presence of an `e` tag.
|
|
613
|
-
// CEP-8 notifications are correlated (include `e`) but are still notifications.
|
|
614
|
-
if (isJSONRPCResultResponse(mcpMessage) ||
|
|
615
|
-
isJSONRPCErrorResponse(mcpMessage)) {
|
|
616
|
-
if (!eTag) {
|
|
617
|
-
this.logger.warn('Received JSON-RPC response without correlation `e` tag', {
|
|
618
|
-
eventId: nostrEvent.id,
|
|
619
|
-
});
|
|
620
|
-
return;
|
|
621
|
-
}
|
|
622
|
-
if (!this.correlationStore.hasPendingRequest(eTag)) {
|
|
623
|
-
this.logger.warn('Received response for unknown/expired request', {
|
|
624
|
-
eventId: nostrEvent.id,
|
|
625
|
-
eTag,
|
|
626
|
-
reason: 'Request not found in pending set - may be duplicate or late response',
|
|
627
|
-
});
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
// Capture outer Nostr event envelope for capability list JSON-RPC responses.
|
|
631
|
-
// This allows consumers to inspect Nostr tags (e.g. CEP-8 `cap` tags)
|
|
632
|
-
// that are not present in the JSON-RPC payload.
|
|
633
|
-
if (isJSONRPCResultResponse(mcpMessage)) {
|
|
634
|
-
const result = mcpMessage.result;
|
|
635
|
-
if (ListToolsResultSchema.safeParse(result).success) {
|
|
636
|
-
this.serverToolsListEvent = nostrEvent;
|
|
637
|
-
}
|
|
638
|
-
else if (ListResourcesResultSchema.safeParse(result).success) {
|
|
639
|
-
this.serverResourcesListEvent = nostrEvent;
|
|
640
|
-
}
|
|
641
|
-
else if (ListResourceTemplatesResultSchema.safeParse(result).success) {
|
|
642
|
-
this.serverResourceTemplatesListEvent = nostrEvent;
|
|
643
|
-
}
|
|
644
|
-
else if (ListPromptsResultSchema.safeParse(result).success) {
|
|
645
|
-
this.serverPromptsListEvent = nostrEvent;
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
this.handleResponse(eTag, mcpMessage);
|
|
649
|
-
return;
|
|
650
|
-
}
|
|
651
|
-
if (isJSONRPCNotification(mcpMessage)) {
|
|
652
|
-
this.handleNotification(nostrEvent.id, eTag !== null && eTag !== void 0 ? eTag : undefined, mcpMessage);
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
this.logger.warn('Received unsupported JSON-RPC message type', {
|
|
656
|
-
eventId: nostrEvent.id,
|
|
657
|
-
hasETag: !!eTag,
|
|
658
|
-
});
|
|
659
|
-
}
|
|
660
|
-
catch (error) {
|
|
661
|
-
this.logger.error('Error handling incoming Nostr event', {
|
|
662
|
-
error: error instanceof Error ? error.message : String(error),
|
|
663
|
-
stack: error instanceof Error ? error.stack : undefined,
|
|
664
|
-
eventId: event.id,
|
|
665
|
-
pubkey: event.pubkey,
|
|
666
|
-
kind: event.kind,
|
|
667
|
-
});
|
|
668
|
-
(_b = this.onerror) === null || _b === void 0 ? void 0 : _b.call(this, error instanceof Error
|
|
669
|
-
? error
|
|
670
|
-
: new Error('Failed to handle incoming Nostr event'));
|
|
671
|
-
}
|
|
331
|
+
await this.inboundCoordinator.processIncomingEvent(event);
|
|
672
332
|
}
|
|
673
333
|
/**
|
|
674
334
|
* Gets the server's initialize event if received.
|
|
675
335
|
* @returns The server initialize event or undefined
|
|
676
336
|
*/
|
|
677
337
|
getServerInitializeEvent() {
|
|
678
|
-
return this.
|
|
338
|
+
return this.metadataStore.getServerInitializeEvent();
|
|
679
339
|
}
|
|
680
340
|
/**
|
|
681
341
|
* Gets the parsed initialize result from the server's initialize event content.
|
|
682
342
|
* @returns The parsed initialize result or undefined when unavailable or invalid
|
|
683
343
|
*/
|
|
684
344
|
getServerInitializeResult() {
|
|
685
|
-
|
|
686
|
-
return undefined;
|
|
687
|
-
}
|
|
688
|
-
try {
|
|
689
|
-
const content = JSON.parse(this.serverInitializeEvent.content);
|
|
690
|
-
const parse = InitializeResultSchema.safeParse(content.result);
|
|
691
|
-
return parse.success ? parse.data : undefined;
|
|
692
|
-
}
|
|
693
|
-
catch (_a) {
|
|
694
|
-
return undefined;
|
|
695
|
-
}
|
|
345
|
+
return this.metadataStore.getServerInitializeResult();
|
|
696
346
|
}
|
|
697
347
|
/**
|
|
698
348
|
* Returns whether the server initialize event advertises encrypted transport support.
|
|
699
349
|
* @returns True when the initialize event contains the support_encryption tag
|
|
700
350
|
*/
|
|
701
351
|
serverSupportsEncryption() {
|
|
702
|
-
return
|
|
703
|
-
.isFlag;
|
|
352
|
+
return this.metadataStore.serverSupportsEncryption();
|
|
704
353
|
}
|
|
705
354
|
/**
|
|
706
355
|
* Returns whether the server initialize event advertises ephemeral gift wrap support.
|
|
707
356
|
* @returns True when the initialize event contains the support_encryption_ephemeral tag
|
|
708
357
|
*/
|
|
709
358
|
serverSupportsEphemeralEncryption() {
|
|
710
|
-
return
|
|
359
|
+
return this.metadataStore.serverSupportsEphemeralEncryption();
|
|
711
360
|
}
|
|
712
361
|
/**
|
|
713
362
|
* Gets the server name tag from the initialize event.
|
|
714
363
|
* @returns The name tag value or undefined
|
|
715
364
|
*/
|
|
716
365
|
getServerInitializeName() {
|
|
717
|
-
|
|
718
|
-
return getNostrEventTag((_b = (_a = this.serverInitializeEvent) === null || _a === void 0 ? void 0 : _a.tags) !== null && _b !== void 0 ? _b : [], NOSTR_TAGS.NAME);
|
|
366
|
+
return this.metadataStore.getServerInitializeName();
|
|
719
367
|
}
|
|
720
368
|
/**
|
|
721
369
|
* Gets the server about tag from the initialize event.
|
|
722
370
|
* @returns The about tag value or undefined
|
|
723
371
|
*/
|
|
724
372
|
getServerInitializeAbout() {
|
|
725
|
-
|
|
726
|
-
return getNostrEventTag((_b = (_a = this.serverInitializeEvent) === null || _a === void 0 ? void 0 : _a.tags) !== null && _b !== void 0 ? _b : [], NOSTR_TAGS.ABOUT);
|
|
373
|
+
return this.metadataStore.getServerInitializeAbout();
|
|
727
374
|
}
|
|
728
375
|
/**
|
|
729
376
|
* Gets the server website tag from the initialize event.
|
|
730
377
|
* @returns The website tag value or undefined
|
|
731
378
|
*/
|
|
732
379
|
getServerInitializeWebsite() {
|
|
733
|
-
|
|
734
|
-
return getNostrEventTag((_b = (_a = this.serverInitializeEvent) === null || _a === void 0 ? void 0 : _a.tags) !== null && _b !== void 0 ? _b : [], NOSTR_TAGS.WEBSITE);
|
|
380
|
+
return this.metadataStore.getServerInitializeWebsite();
|
|
735
381
|
}
|
|
736
382
|
/**
|
|
737
383
|
* Gets the server picture tag from the initialize event.
|
|
738
384
|
* @returns The picture tag value or undefined
|
|
739
385
|
*/
|
|
740
386
|
getServerInitializePicture() {
|
|
741
|
-
|
|
742
|
-
return getNostrEventTag((_b = (_a = this.serverInitializeEvent) === null || _a === void 0 ? void 0 : _a.tags) !== null && _b !== void 0 ? _b : [], NOSTR_TAGS.PICTURE);
|
|
387
|
+
return this.metadataStore.getServerInitializePicture();
|
|
743
388
|
}
|
|
744
389
|
/** Gets the server's most recently observed tools/list event envelope, if any. */
|
|
745
390
|
getServerToolsListEvent() {
|
|
746
|
-
return this.
|
|
391
|
+
return this.metadataStore.getServerToolsListEvent();
|
|
747
392
|
}
|
|
748
393
|
/** Gets the server's most recently observed resources/list event envelope, if any. */
|
|
749
394
|
getServerResourcesListEvent() {
|
|
750
|
-
return this.
|
|
395
|
+
return this.metadataStore.getServerResourcesListEvent();
|
|
751
396
|
}
|
|
752
397
|
/** Gets the server's most recently observed resources/templates/list event envelope, if any. */
|
|
753
398
|
getServerResourceTemplatesListEvent() {
|
|
754
|
-
return this.
|
|
399
|
+
return this.metadataStore.getServerResourceTemplatesListEvent();
|
|
755
400
|
}
|
|
756
401
|
/** Gets the server's most recently observed prompts/list event envelope, if any. */
|
|
757
402
|
getServerPromptsListEvent() {
|
|
758
|
-
return this.
|
|
759
|
-
}
|
|
760
|
-
learnServerDiscovery(event) {
|
|
761
|
-
if (!Array.isArray(event.tags)) {
|
|
762
|
-
return;
|
|
763
|
-
}
|
|
764
|
-
const discovered = parseDiscoveredPeerCapabilities(event.tags);
|
|
765
|
-
if (discovered.discoveryTags.length === 0) {
|
|
766
|
-
return;
|
|
767
|
-
}
|
|
768
|
-
this.serverSupportsEphemeralGiftWraps || (this.serverSupportsEphemeralGiftWraps = discovered.supportsEphemeralEncryption);
|
|
769
|
-
this.serverSupportsOversizedTransfer || (this.serverSupportsOversizedTransfer = discovered.supportsOversizedTransfer);
|
|
770
|
-
this.serverSupportsOpenStream || (this.serverSupportsOpenStream = discovered.supportsOpenStream);
|
|
771
|
-
if (!this.serverInitializeEvent) {
|
|
772
|
-
this.serverInitializeEvent = event;
|
|
773
|
-
this.logger.info('Learned server discovery tags from inbound event', {
|
|
774
|
-
eventId: event.id,
|
|
775
|
-
});
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
778
|
-
const currentHasInitializeResult = InitializeResultSchema.safeParse(this.getInitializeResultCandidate(event)).success;
|
|
779
|
-
const existingHasInitializeResult = InitializeResultSchema.safeParse(this.getInitializeResultCandidate(this.serverInitializeEvent)).success;
|
|
780
|
-
if (!existingHasInitializeResult && currentHasInitializeResult) {
|
|
781
|
-
this.serverInitializeEvent = event;
|
|
782
|
-
this.logger.info('Upgraded learned server discovery event to initialize response', {
|
|
783
|
-
eventId: event.id,
|
|
784
|
-
});
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
getInitializeResultCandidate(event) {
|
|
788
|
-
try {
|
|
789
|
-
const content = JSON.parse(event.content);
|
|
790
|
-
return content.result;
|
|
791
|
-
}
|
|
792
|
-
catch (_a) {
|
|
793
|
-
return undefined;
|
|
794
|
-
}
|
|
403
|
+
return this.metadataStore.getServerPromptsListEvent();
|
|
795
404
|
}
|
|
796
405
|
async resolveOperationalRelayHandler() {
|
|
797
406
|
var _a, _b, _c;
|
|
@@ -838,7 +447,7 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
838
447
|
* @param mcpMessage - The JSON-RPC notification message
|
|
839
448
|
*/
|
|
840
449
|
handleNotification(eventId, correlatedEventId, mcpMessage) {
|
|
841
|
-
var _a, _b, _c
|
|
450
|
+
var _a, _b, _c;
|
|
842
451
|
try {
|
|
843
452
|
const result = NotificationSchema.safeParse(mcpMessage);
|
|
844
453
|
if (!result.success) {
|
|
@@ -857,59 +466,8 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
857
466
|
});
|
|
858
467
|
return;
|
|
859
468
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
mcpMessage.method === 'notifications/progress' &&
|
|
863
|
-
OpenStreamReceiver.isOpenStreamFrame(mcpMessage)) {
|
|
864
|
-
this.openStreamReceiver
|
|
865
|
-
.processFrame(mcpMessage)
|
|
866
|
-
.catch((err) => {
|
|
867
|
-
var _a;
|
|
868
|
-
this.logger.error('Open stream error (client)', {
|
|
869
|
-
error: err instanceof Error ? err.message : String(err),
|
|
870
|
-
});
|
|
871
|
-
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
|
|
872
|
-
});
|
|
873
|
-
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, mcpMessage);
|
|
874
|
-
(_b = this.onmessageWithContext) === null || _b === void 0 ? void 0 : _b.call(this, mcpMessage, {
|
|
875
|
-
eventId,
|
|
876
|
-
correlatedEventId,
|
|
877
|
-
});
|
|
878
|
-
return;
|
|
879
|
-
}
|
|
880
|
-
if (isJSONRPCNotification(mcpMessage) &&
|
|
881
|
-
mcpMessage.method === 'notifications/progress' &&
|
|
882
|
-
OversizedTransferReceiver.isOversizedFrame(mcpMessage)) {
|
|
883
|
-
this.oversizedReceiver
|
|
884
|
-
.processFrame(mcpMessage)
|
|
885
|
-
.then((synthetic) => {
|
|
886
|
-
if (synthetic !== null) {
|
|
887
|
-
if (isJSONRPCResultResponse(synthetic) ||
|
|
888
|
-
isJSONRPCErrorResponse(synthetic)) {
|
|
889
|
-
if (correlatedEventId) {
|
|
890
|
-
this.handleResponse(correlatedEventId, synthetic);
|
|
891
|
-
}
|
|
892
|
-
else {
|
|
893
|
-
this.logger.warn('Oversized response completed without correlation `e` tag', {
|
|
894
|
-
eventId,
|
|
895
|
-
});
|
|
896
|
-
}
|
|
897
|
-
return;
|
|
898
|
-
}
|
|
899
|
-
this.handleNotification(eventId, correlatedEventId, synthetic);
|
|
900
|
-
}
|
|
901
|
-
})
|
|
902
|
-
.catch((err) => {
|
|
903
|
-
var _a;
|
|
904
|
-
this.logger.error('Oversized transfer error (client)', {
|
|
905
|
-
error: err instanceof Error ? err.message : String(err),
|
|
906
|
-
});
|
|
907
|
-
(_a = this.onerror) === null || _a === void 0 ? void 0 : _a.call(this, err instanceof Error ? err : new Error(String(err)));
|
|
908
|
-
});
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
|
-
(_c = this.onmessage) === null || _c === void 0 ? void 0 : _c.call(this, mcpMessage);
|
|
912
|
-
(_d = this.onmessageWithContext) === null || _d === void 0 ? void 0 : _d.call(this, mcpMessage, {
|
|
469
|
+
(_a = this.onmessage) === null || _a === void 0 ? void 0 : _a.call(this, mcpMessage);
|
|
470
|
+
(_b = this.onmessageWithContext) === null || _b === void 0 ? void 0 : _b.call(this, mcpMessage, {
|
|
913
471
|
eventId,
|
|
914
472
|
correlatedEventId,
|
|
915
473
|
});
|
|
@@ -919,11 +477,17 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
919
477
|
error: error instanceof Error ? error.message : String(error),
|
|
920
478
|
stack: error instanceof Error ? error.stack : undefined,
|
|
921
479
|
});
|
|
922
|
-
(
|
|
480
|
+
(_c = this.onerror) === null || _c === void 0 ? void 0 : _c.call(this, error instanceof Error
|
|
923
481
|
? error
|
|
924
482
|
: new Error('Failed to handle incoming notification'));
|
|
925
483
|
}
|
|
926
484
|
}
|
|
485
|
+
buildOutboundClientTags(params) {
|
|
486
|
+
return this.capabilityNegotiator.buildOutboundTags(params);
|
|
487
|
+
}
|
|
488
|
+
chooseOutboundGiftWrapKind() {
|
|
489
|
+
return this.capabilityNegotiator.chooseOutboundGiftWrapKind();
|
|
490
|
+
}
|
|
927
491
|
/**
|
|
928
492
|
* Test-only accessor for internal state.
|
|
929
493
|
* @internal
|
|
@@ -937,13 +501,13 @@ export class NostrClientTransport extends BaseNostrTransport {
|
|
|
937
501
|
discoveryRelayUrls: [...this.discoveryRelayUrls],
|
|
938
502
|
fallbackOperationalRelayUrls: [...this.fallbackOperationalRelayUrls],
|
|
939
503
|
relayUrls: (_c = (_b = (_a = this.relayHandler).getRelayUrls) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : [],
|
|
940
|
-
serverInitializeEvent: this.
|
|
941
|
-
serverToolsListEvent: this.
|
|
942
|
-
serverResourcesListEvent: this.
|
|
943
|
-
serverResourceTemplatesListEvent: this.
|
|
944
|
-
serverPromptsListEvent: this.
|
|
504
|
+
serverInitializeEvent: this.metadataStore.getServerInitializeEvent(),
|
|
505
|
+
serverToolsListEvent: this.metadataStore.getServerToolsListEvent(),
|
|
506
|
+
serverResourcesListEvent: this.metadataStore.getServerResourcesListEvent(),
|
|
507
|
+
serverResourceTemplatesListEvent: this.metadataStore.getServerResourceTemplatesListEvent(),
|
|
508
|
+
serverPromptsListEvent: this.metadataStore.getServerPromptsListEvent(),
|
|
945
509
|
oversizedReceiver: this.oversizedReceiver,
|
|
946
|
-
openStreamReceiver: this.
|
|
510
|
+
openStreamReceiver: this.openStreamFactory.getReceiver(),
|
|
947
511
|
};
|
|
948
512
|
}
|
|
949
513
|
}
|