Skip to content

Commit b2b426f

Browse files
authored
Merge pull request #560 from daidi/main
fix: Ensure _meta object is not lost when onprogress option is passed
2 parents df0d9c4 + cdcb009 commit b2b426f

File tree

2 files changed

+130
-1
lines changed

2 files changed

+130
-1
lines changed

src/shared/protocol.test.ts

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,11 @@ class MockTransport implements Transport {
2727
describe("protocol tests", () => {
2828
let protocol: Protocol<Request, Notification, Result>;
2929
let transport: MockTransport;
30+
let sendSpy: jest.SpyInstance;
3031

3132
beforeEach(() => {
3233
transport = new MockTransport();
34+
sendSpy = jest.spyOn(transport, 'send');
3335
protocol = new (class extends Protocol<Request, Notification, Result> {
3436
protected assertCapabilityForMethod(): void {}
3537
protected assertNotificationCapability(): void {}
@@ -63,6 +65,130 @@ describe("protocol tests", () => {
6365
expect(oncloseMock).toHaveBeenCalled();
6466
});
6567

68+
describe("_meta preservation with onprogress", () => {
69+
test("should preserve existing _meta when adding progressToken", async () => {
70+
await protocol.connect(transport);
71+
const request = {
72+
method: "example",
73+
params: {
74+
data: "test",
75+
_meta: {
76+
customField: "customValue",
77+
anotherField: 123
78+
}
79+
}
80+
};
81+
const mockSchema: ZodType<{ result: string }> = z.object({
82+
result: z.string(),
83+
});
84+
const onProgressMock = jest.fn();
85+
86+
protocol.request(request, mockSchema, {
87+
onprogress: onProgressMock,
88+
});
89+
90+
expect(sendSpy).toHaveBeenCalledWith(expect.objectContaining({
91+
method: "example",
92+
params: {
93+
data: "test",
94+
_meta: {
95+
customField: "customValue",
96+
anotherField: 123,
97+
progressToken: expect.any(Number)
98+
}
99+
},
100+
jsonrpc: "2.0",
101+
id: expect.any(Number)
102+
}), expect.any(Object));
103+
});
104+
105+
test("should create _meta with progressToken when no _meta exists", async () => {
106+
await protocol.connect(transport);
107+
const request = {
108+
method: "example",
109+
params: {
110+
data: "test"
111+
}
112+
};
113+
const mockSchema: ZodType<{ result: string }> = z.object({
114+
result: z.string(),
115+
});
116+
const onProgressMock = jest.fn();
117+
118+
protocol.request(request, mockSchema, {
119+
onprogress: onProgressMock,
120+
});
121+
122+
expect(sendSpy).toHaveBeenCalledWith(expect.objectContaining({
123+
method: "example",
124+
params: {
125+
data: "test",
126+
_meta: {
127+
progressToken: expect.any(Number)
128+
}
129+
},
130+
jsonrpc: "2.0",
131+
id: expect.any(Number)
132+
}), expect.any(Object));
133+
});
134+
135+
test("should not modify _meta when onprogress is not provided", async () => {
136+
await protocol.connect(transport);
137+
const request = {
138+
method: "example",
139+
params: {
140+
data: "test",
141+
_meta: {
142+
customField: "customValue"
143+
}
144+
}
145+
};
146+
const mockSchema: ZodType<{ result: string }> = z.object({
147+
result: z.string(),
148+
});
149+
150+
protocol.request(request, mockSchema);
151+
152+
expect(sendSpy).toHaveBeenCalledWith(expect.objectContaining({
153+
method: "example",
154+
params: {
155+
data: "test",
156+
_meta: {
157+
customField: "customValue"
158+
}
159+
},
160+
jsonrpc: "2.0",
161+
id: expect.any(Number)
162+
}), expect.any(Object));
163+
});
164+
165+
test("should handle params being undefined with onprogress", async () => {
166+
await protocol.connect(transport);
167+
const request = {
168+
method: "example"
169+
};
170+
const mockSchema: ZodType<{ result: string }> = z.object({
171+
result: z.string(),
172+
});
173+
const onProgressMock = jest.fn();
174+
175+
protocol.request(request, mockSchema, {
176+
onprogress: onProgressMock,
177+
});
178+
179+
expect(sendSpy).toHaveBeenCalledWith(expect.objectContaining({
180+
method: "example",
181+
params: {
182+
_meta: {
183+
progressToken: expect.any(Number)
184+
}
185+
},
186+
jsonrpc: "2.0",
187+
id: expect.any(Number)
188+
}), expect.any(Object));
189+
});
190+
});
191+
66192
describe("progress notification timeout behavior", () => {
67193
beforeEach(() => {
68194
jest.useFakeTimers();

src/shared/protocol.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,10 @@ export abstract class Protocol<
541541
this._progressHandlers.set(messageId, options.onprogress);
542542
jsonrpcRequest.params = {
543543
...request.params,
544-
_meta: { progressToken: messageId },
544+
_meta: {
545+
...(request.params?._meta || {}),
546+
progressToken: messageId
547+
},
545548
};
546549
}
547550

0 commit comments

Comments
 (0)