Skip to content

Commit 0e053fe

Browse files
fix(core): send transformed parsed.data in sendCustom* schema-bundle overloads
The schema-bundle overload validated params via parseSchema but discarded parsed.data and sent the raw input over the wire. Zod transforms (.trim(), .toLowerCase()) and defaults (.default(n)) were silently dropped. Now sends parsed.data after successful validation. The overload's params type changed from SchemaOutput<P> to SchemaInput<P> since callers pass pre-transform input. Adds SchemaInput<T> = z.input<T> to schema utils.
1 parent 07c5491 commit 0e053fe

3 files changed

Lines changed: 22 additions & 3 deletions

File tree

packages/core/src/shared/protocol.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import {
4646
ProtocolErrorCode,
4747
SUPPORTED_PROTOCOL_VERSIONS
4848
} from '../types/index.js';
49-
import type { AnySchema, SchemaOutput } from '../util/schema.js';
49+
import type { AnySchema, SchemaInput, SchemaOutput } from '../util/schema.js';
5050
import { parseSchema } from '../util/schema.js';
5151
import type { TaskContext, TaskManagerHost, TaskManagerOptions, TaskRequestOptions } from './taskManager.js';
5252
import { NullTaskManager, TaskManager } from './taskManager.js';
@@ -1146,7 +1146,7 @@ export abstract class Protocol<ContextT extends BaseContext> {
11461146
*/
11471147
sendCustomRequest<P extends AnySchema, R extends AnySchema>(
11481148
method: string,
1149-
params: SchemaOutput<P>,
1149+
params: SchemaInput<P>,
11501150
schemas: { params: P; result: R },
11511151
options?: RequestOptions
11521152
): Promise<SchemaOutput<R>>;
@@ -1168,6 +1168,7 @@ export abstract class Protocol<ContextT extends BaseContext> {
11681168
if (!parsed.success) {
11691169
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid params for ${method}: ${parsed.error.message}`);
11701170
}
1171+
params = parsed.data as Record<string, unknown> | undefined;
11711172
resultSchema = schemaOrBundle.result;
11721173
} else {
11731174
resultSchema = schemaOrBundle;
@@ -1189,7 +1190,7 @@ export abstract class Protocol<ContextT extends BaseContext> {
11891190
*/
11901191
sendCustomNotification<P extends AnySchema>(
11911192
method: string,
1192-
params: SchemaOutput<P>,
1193+
params: SchemaInput<P>,
11931194
schemas: { params: P },
11941195
options?: NotificationOptions
11951196
): Promise<void>;
@@ -1206,6 +1207,7 @@ export abstract class Protocol<ContextT extends BaseContext> {
12061207
if (!parsed.success) {
12071208
throw new ProtocolError(ProtocolErrorCode.InvalidParams, `Invalid params for ${method}: ${parsed.error.message}`);
12081209
}
1210+
params = parsed.data as Record<string, unknown> | undefined;
12091211
options = maybeOptions;
12101212
} else {
12111213
options = schemasOrOptions;

packages/core/src/util/schema.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ export type AnyObjectSchema = z.core.$ZodObject;
2020
*/
2121
export type SchemaOutput<T extends AnySchema> = z.output<T>;
2222

23+
/**
24+
* Extracts the input type from a Zod schema (pre-transform / pre-default).
25+
*/
26+
export type SchemaInput<T extends AnySchema> = z.input<T>;
27+
2328
/**
2429
* Parses data against a Zod schema (synchronous).
2530
* Returns a discriminated union with success/error.

packages/core/test/shared/customMethods.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,18 @@ describe('sendCustomRequest', () => {
191191
})
192192
).rejects.toSatisfy((e: unknown) => e instanceof ProtocolError && e.code === ProtocolErrorCode.InvalidParams);
193193
});
194+
195+
test('schema bundle overload: transforms and defaults applied to outbound params', async () => {
196+
const [client, server] = await linkedPair();
197+
const ParamsWithTransforms = z.object({ query: z.string().trim(), page: z.number().default(1) });
198+
let received: unknown;
199+
server.setCustomRequestHandler('acme/q', z.unknown(), p => {
200+
received = p;
201+
return {};
202+
});
203+
await client.sendCustomRequest('acme/q', { query: ' hi ' }, { params: ParamsWithTransforms, result: z.object({}) });
204+
expect(received).toEqual({ query: 'hi', page: 1 });
205+
});
194206
});
195207

196208
describe('sendCustomNotification', () => {

0 commit comments

Comments
 (0)