@trpc/server 11.0.0-rc.340 → 11.0.0-rc.345
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/@trpc/server/http.d.ts +0 -1
- package/dist/@trpc/server/http.d.ts.map +1 -1
- package/dist/@trpc/server/index.d.ts +2 -1
- package/dist/@trpc/server/index.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/content-type/json/index.d.ts +10 -0
- package/dist/adapters/aws-lambda/content-type/json/index.d.ts.map +1 -0
- package/dist/adapters/aws-lambda/content-type/json/index.js +59 -0
- package/dist/adapters/aws-lambda/content-type/json/index.mjs +57 -0
- package/dist/adapters/aws-lambda/index.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/index.js +19 -9
- package/dist/adapters/aws-lambda/index.mjs +19 -9
- package/dist/adapters/aws-lambda/utils.d.ts +3 -12
- package/dist/adapters/aws-lambda/utils.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/utils.js +12 -1
- package/dist/adapters/aws-lambda/utils.mjs +12 -2
- package/dist/adapters/content-handlers/selectContentHandlerOrUnsupportedMediaType.d.ts +4 -0
- package/dist/adapters/content-handlers/selectContentHandlerOrUnsupportedMediaType.d.ts.map +1 -0
- package/dist/adapters/content-handlers/selectContentHandlerOrUnsupportedMediaType.js +22 -0
- package/dist/adapters/content-handlers/selectContentHandlerOrUnsupportedMediaType.mjs +20 -0
- package/dist/adapters/express.d.ts.map +1 -1
- package/dist/adapters/express.js +0 -1
- package/dist/adapters/express.mjs +0 -1
- package/dist/adapters/fastify/content-type/json/index.d.ts +8 -0
- package/dist/adapters/fastify/content-type/json/index.d.ts.map +1 -0
- package/dist/adapters/fastify/content-type/json/index.js +59 -0
- package/dist/adapters/fastify/content-type/json/index.mjs +57 -0
- package/dist/adapters/fastify/fastifyRequestHandler.d.ts +1 -9
- package/dist/adapters/fastify/fastifyRequestHandler.d.ts.map +1 -1
- package/dist/adapters/fastify/fastifyRequestHandler.js +10 -2
- package/dist/adapters/fastify/fastifyRequestHandler.mjs +10 -2
- package/dist/adapters/fastify/fastifyTRPCPlugin.d.ts +1 -1
- package/dist/adapters/fastify/fastifyTRPCPlugin.d.ts.map +1 -1
- package/dist/adapters/fastify/types.d.ts +11 -0
- package/dist/adapters/fastify/types.d.ts.map +1 -0
- package/dist/adapters/fetch/content-type/json/index.d.ts +9 -0
- package/dist/adapters/fetch/content-type/json/index.d.ts.map +1 -0
- package/dist/adapters/fetch/content-type/json/index.js +58 -0
- package/dist/adapters/fetch/content-type/json/index.mjs +56 -0
- package/dist/adapters/fetch/fetchRequestHandler.d.ts +1 -5
- package/dist/adapters/fetch/fetchRequestHandler.d.ts.map +1 -1
- package/dist/adapters/fetch/fetchRequestHandler.js +16 -2
- package/dist/adapters/fetch/fetchRequestHandler.mjs +16 -2
- package/dist/adapters/fetch/types.d.ts +9 -12
- package/dist/adapters/fetch/types.d.ts.map +1 -1
- package/dist/adapters/next-app-dir/nextAppDirCaller.d.ts +2 -7
- package/dist/adapters/next-app-dir/nextAppDirCaller.d.ts.map +1 -1
- package/dist/adapters/next.d.ts.map +1 -1
- package/dist/adapters/next.js +0 -1
- package/dist/adapters/next.mjs +0 -1
- package/dist/adapters/node-http/content-type/form-data/fileUploadHandler.js +0 -72
- package/dist/adapters/node-http/content-type/form-data/fileUploadHandler.mjs +5 -76
- package/dist/adapters/node-http/content-type/form-data/index.d.ts +5 -19
- package/dist/adapters/node-http/content-type/form-data/index.d.ts.map +1 -1
- package/dist/adapters/node-http/content-type/form-data/index.js +14 -39
- package/dist/adapters/node-http/content-type/form-data/index.mjs +15 -35
- package/dist/adapters/node-http/content-type/form-data/streamSlice.d.ts +2 -2
- package/dist/adapters/node-http/content-type/form-data/streamSlice.d.ts.map +1 -1
- package/dist/adapters/node-http/content-type/form-data/uploadHandler.js +0 -12
- package/dist/adapters/node-http/content-type/form-data/uploadHandler.mjs +1 -12
- package/dist/adapters/node-http/content-type/json/getPostBody.d.ts.map +1 -1
- package/dist/adapters/node-http/content-type/json/getPostBody.js +4 -12
- package/dist/adapters/node-http/content-type/json/getPostBody.mjs +4 -12
- package/dist/adapters/node-http/content-type/json/index.d.ts +4 -1
- package/dist/adapters/node-http/content-type/json/index.d.ts.map +1 -1
- package/dist/adapters/node-http/content-type/json/index.js +59 -10
- package/dist/adapters/node-http/content-type/json/index.mjs +59 -10
- package/dist/adapters/node-http/content-type/octet/index.d.ts +5 -0
- package/dist/adapters/node-http/content-type/octet/index.d.ts.map +1 -0
- package/dist/adapters/node-http/content-type/octet/index.js +19 -0
- package/dist/adapters/node-http/content-type/octet/index.mjs +17 -0
- package/dist/adapters/node-http/content-type/types.d.ts +8 -0
- package/dist/adapters/node-http/content-type/types.d.ts.map +1 -0
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +1 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.js +19 -21
- package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +20 -22
- package/dist/adapters/node-http/types.d.ts +8 -19
- package/dist/adapters/node-http/types.d.ts.map +1 -1
- package/dist/adapters/standalone.d.ts.map +1 -1
- package/dist/adapters/standalone.js +0 -1
- package/dist/adapters/standalone.mjs +0 -1
- package/dist/adapters/ws.d.ts +2 -12
- package/dist/adapters/ws.d.ts.map +1 -1
- package/dist/bundle-analysis.json +266 -207
- package/dist/http.js +0 -2
- package/dist/http.mjs +0 -1
- package/dist/index.js +2 -0
- package/dist/index.mjs +1 -0
- package/dist/unstable-core-do-not-import/contentTypeParsers.d.ts +16 -0
- package/dist/unstable-core-do-not-import/contentTypeParsers.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/contentTypeParsers.js +23 -0
- package/dist/unstable-core-do-not-import/contentTypeParsers.mjs +21 -0
- package/dist/unstable-core-do-not-import/http/contentType.d.ts +6 -14
- package/dist/unstable-core-do-not-import/http/contentType.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/index.d.ts +0 -1
- package/dist/unstable-core-do-not-import/http/index.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/resolveHTTPResponse.d.ts +5 -5
- package/dist/unstable-core-do-not-import/http/resolveHTTPResponse.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/resolveHTTPResponse.js +25 -22
- package/dist/unstable-core-do-not-import/http/resolveHTTPResponse.mjs +25 -22
- package/dist/unstable-core-do-not-import/http/types.d.ts +0 -2
- package/dist/unstable-core-do-not-import/http/types.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/rootConfig.d.ts +21 -0
- package/dist/unstable-core-do-not-import/rootConfig.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import.js +0 -2
- package/dist/unstable-core-do-not-import.mjs +0 -1
- package/package.json +3 -3
- package/src/@trpc/server/http.ts +0 -1
- package/src/@trpc/server/index.ts +7 -0
- package/src/adapters/aws-lambda/content-type/json/index.ts +99 -0
- package/src/adapters/aws-lambda/index.ts +24 -9
- package/src/adapters/aws-lambda/utils.ts +21 -15
- package/src/adapters/content-handlers/selectContentHandlerOrUnsupportedMediaType.ts +21 -0
- package/src/adapters/express.ts +1 -6
- package/src/adapters/fastify/content-type/json/index.ts +97 -0
- package/src/adapters/fastify/fastifyRequestHandler.ts +15 -21
- package/src/adapters/fastify/fastifyTRPCPlugin.ts +1 -1
- package/src/adapters/fastify/types.ts +22 -0
- package/src/adapters/fetch/content-type/json/index.ts +96 -0
- package/src/adapters/fetch/fetchRequestHandler.ts +22 -10
- package/src/adapters/fetch/types.ts +22 -15
- package/src/adapters/next-app-dir/nextAppDirCaller.ts +2 -9
- package/src/adapters/next.ts +1 -6
- package/src/adapters/node-http/content-type/form-data/fileUploadHandler.ts +7 -7
- package/src/adapters/node-http/content-type/form-data/index.ts +29 -51
- package/src/adapters/node-http/content-type/form-data/streamSlice.ts +2 -2
- package/src/adapters/node-http/content-type/json/getPostBody.ts +9 -18
- package/src/adapters/node-http/content-type/json/index.ts +85 -5
- package/src/adapters/node-http/content-type/octet/index.ts +29 -0
- package/src/adapters/node-http/{internals/contentType.ts → content-type/types.ts} +2 -14
- package/src/adapters/node-http/nodeHTTPRequestHandler.ts +22 -35
- package/src/adapters/node-http/types.ts +46 -46
- package/src/adapters/standalone.ts +1 -2
- package/src/adapters/ws.ts +9 -14
- package/src/unstable-core-do-not-import/contentTypeParsers.ts +37 -0
- package/src/unstable-core-do-not-import/http/contentType.ts +9 -84
- package/src/unstable-core-do-not-import/http/index.ts +0 -1
- package/src/unstable-core-do-not-import/http/resolveHTTPResponse.ts +29 -28
- package/src/unstable-core-do-not-import/http/types.ts +0 -2
- package/src/unstable-core-do-not-import/rootConfig.ts +31 -0
- package/dist/adapters/node-http/internals/contentType.d.ts +0 -9
- package/dist/adapters/node-http/internals/contentType.d.ts.map +0 -1
- package/dist/adapters/node-http/internals/contentType.js +0 -8
- package/dist/adapters/node-http/internals/contentType.mjs +0 -6
- package/dist/unstable-core-do-not-import/http/contentType.js +0 -54
- package/dist/unstable-core-do-not-import/http/contentType.mjs +0 -52
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
// @trpc/server
|
|
2
|
+
import { TRPCError } from '../../../../@trpc/server';
|
|
3
|
+
import type {
|
|
4
|
+
AnyRouter,
|
|
5
|
+
CombinedDataTransformer,
|
|
6
|
+
} from '../../../../@trpc/server';
|
|
7
|
+
import type {
|
|
8
|
+
BaseContentTypeHandler,
|
|
9
|
+
HTTPRequest,
|
|
10
|
+
} from '../../../../@trpc/server/http';
|
|
11
|
+
import {
|
|
12
|
+
lambdaEventToHTTPBody,
|
|
13
|
+
type APIGatewayEvent,
|
|
14
|
+
type AWSLambdaOptions,
|
|
15
|
+
} from '../../utils';
|
|
16
|
+
|
|
17
|
+
export interface LambdaHTTPContentTypeHandler<
|
|
18
|
+
TRouter extends AnyRouter,
|
|
19
|
+
TEvent extends APIGatewayEvent,
|
|
20
|
+
> extends BaseContentTypeHandler<
|
|
21
|
+
AWSLambdaOptions<TRouter, TEvent> & {
|
|
22
|
+
event: TEvent;
|
|
23
|
+
req: HTTPRequest;
|
|
24
|
+
}
|
|
25
|
+
> {}
|
|
26
|
+
|
|
27
|
+
export const getLambdaHTTPJSONContentTypeHandler: <
|
|
28
|
+
TRouter extends AnyRouter,
|
|
29
|
+
TEvent extends APIGatewayEvent,
|
|
30
|
+
>() => LambdaHTTPContentTypeHandler<TRouter, TEvent> = () => ({
|
|
31
|
+
name: 'lambda-json',
|
|
32
|
+
isMatch(opts) {
|
|
33
|
+
return !!opts.event.headers['Content-Type']?.startsWith('application/json');
|
|
34
|
+
},
|
|
35
|
+
getInputs: async (opts, info) => {
|
|
36
|
+
function getRawProcedureInputOrThrow() {
|
|
37
|
+
const { event, req } = opts;
|
|
38
|
+
|
|
39
|
+
try {
|
|
40
|
+
if (req.method === 'GET') {
|
|
41
|
+
const input = req.query.get('input');
|
|
42
|
+
if (!input) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return JSON.parse(input);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const body = lambdaEventToHTTPBody(opts.event);
|
|
50
|
+
if (typeof body === 'string') {
|
|
51
|
+
// A mutation with no inputs will have req.body === ''
|
|
52
|
+
return body.length === 0 ? undefined : JSON.parse(body);
|
|
53
|
+
}
|
|
54
|
+
return event.body;
|
|
55
|
+
} catch (cause) {
|
|
56
|
+
throw new TRPCError({
|
|
57
|
+
code: 'PARSE_ERROR',
|
|
58
|
+
cause,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const deserializeInputValue = (
|
|
64
|
+
rawValue: unknown,
|
|
65
|
+
transformer: CombinedDataTransformer,
|
|
66
|
+
) => {
|
|
67
|
+
return typeof rawValue !== 'undefined'
|
|
68
|
+
? transformer.input.deserialize(rawValue)
|
|
69
|
+
: rawValue;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const rawInput = getRawProcedureInputOrThrow();
|
|
73
|
+
if (rawInput === undefined) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const transformer = opts.router._def._config.transformer;
|
|
78
|
+
|
|
79
|
+
if (!info.isBatchCall) {
|
|
80
|
+
return deserializeInputValue(rawInput, transformer);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/* istanbul ignore if */
|
|
84
|
+
if (
|
|
85
|
+
rawInput == null ||
|
|
86
|
+
typeof rawInput !== 'object' ||
|
|
87
|
+
Array.isArray(rawInput)
|
|
88
|
+
) {
|
|
89
|
+
throw new TRPCError({
|
|
90
|
+
code: 'BAD_REQUEST',
|
|
91
|
+
message: '"input" needs to be an object when doing a batch call',
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const rawValue = rawInput[info.batch];
|
|
96
|
+
|
|
97
|
+
return deserializeInputValue(rawValue, transformer);
|
|
98
|
+
},
|
|
99
|
+
});
|
|
@@ -24,6 +24,8 @@ import type {
|
|
|
24
24
|
ResolveHTTPRequestOptionsContextFn,
|
|
25
25
|
} from '../../@trpc/server/http';
|
|
26
26
|
import { resolveHTTPResponse } from '../../@trpc/server/http';
|
|
27
|
+
import { selectContentHandlerOrUnsupportedMediaType } from '../content-handlers/selectContentHandlerOrUnsupportedMediaType';
|
|
28
|
+
import { getLambdaHTTPJSONContentTypeHandler } from './content-type/json';
|
|
27
29
|
import type {
|
|
28
30
|
APIGatewayEvent,
|
|
29
31
|
APIGatewayResult,
|
|
@@ -50,18 +52,10 @@ function lambdaEventToHTTPRequest(event: APIGatewayEvent): HTTPRequest {
|
|
|
50
52
|
}
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
let body: string | null | undefined;
|
|
54
|
-
if (event.body && event.isBase64Encoded) {
|
|
55
|
-
body = Buffer.from(event.body, 'base64').toString('utf8');
|
|
56
|
-
} else {
|
|
57
|
-
body = event.body;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
55
|
return {
|
|
61
56
|
method: getHTTPMethod(event),
|
|
62
57
|
query: query,
|
|
63
58
|
headers: event.headers,
|
|
64
|
-
body: body,
|
|
65
59
|
};
|
|
66
60
|
}
|
|
67
61
|
|
|
@@ -109,18 +103,39 @@ export function awsLambdaRequestHandler<
|
|
|
109
103
|
return async (event, context) => {
|
|
110
104
|
const req = lambdaEventToHTTPRequest(event);
|
|
111
105
|
const path = getPath(event);
|
|
106
|
+
|
|
112
107
|
const createContext: ResolveHTTPRequestOptionsContextFn<TRouter> = async (
|
|
113
108
|
innerOpts,
|
|
114
109
|
) => {
|
|
115
110
|
return await opts.createContext?.({ event, context, ...innerOpts });
|
|
116
111
|
};
|
|
117
112
|
|
|
113
|
+
const [contentTypeHandler, unsupportedMediaTypeError] =
|
|
114
|
+
selectContentHandlerOrUnsupportedMediaType(
|
|
115
|
+
[getLambdaHTTPJSONContentTypeHandler<TRouter, TEvent>()],
|
|
116
|
+
{
|
|
117
|
+
...opts,
|
|
118
|
+
event,
|
|
119
|
+
req,
|
|
120
|
+
},
|
|
121
|
+
);
|
|
122
|
+
|
|
118
123
|
const response = await resolveHTTPResponse({
|
|
119
124
|
...opts,
|
|
120
125
|
createContext,
|
|
121
126
|
req,
|
|
122
127
|
path,
|
|
123
|
-
error:
|
|
128
|
+
error: unsupportedMediaTypeError,
|
|
129
|
+
async getInput(info) {
|
|
130
|
+
return await contentTypeHandler?.getInputs(
|
|
131
|
+
{
|
|
132
|
+
...opts,
|
|
133
|
+
event,
|
|
134
|
+
req,
|
|
135
|
+
},
|
|
136
|
+
info,
|
|
137
|
+
);
|
|
138
|
+
},
|
|
124
139
|
onError(o) {
|
|
125
140
|
opts?.onError?.({
|
|
126
141
|
...o,
|
|
@@ -14,7 +14,12 @@ import type {
|
|
|
14
14
|
APIGatewayProxyStructuredResultV2,
|
|
15
15
|
Context as APIGWContext,
|
|
16
16
|
} from 'aws-lambda';
|
|
17
|
-
import type {
|
|
17
|
+
import type {
|
|
18
|
+
AnyRouter,
|
|
19
|
+
CreateContextCallback,
|
|
20
|
+
inferRouterContext,
|
|
21
|
+
} from '../../@trpc/server';
|
|
22
|
+
// import @trpc/server
|
|
18
23
|
|
|
19
24
|
// @trpc/server
|
|
20
25
|
import { TRPCError } from '../../@trpc/server';
|
|
@@ -50,20 +55,10 @@ export type AWSLambdaOptions<
|
|
|
50
55
|
TEvent extends APIGatewayEvent,
|
|
51
56
|
> =
|
|
52
57
|
| HTTPBaseHandlerOptions<TRouter, TEvent> &
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
**/
|
|
58
|
-
createContext: AWSLambdaCreateContextFn<TRouter, TEvent>;
|
|
59
|
-
}
|
|
60
|
-
| {
|
|
61
|
-
/**
|
|
62
|
-
* @link https://trpc.io/docs/v11/context
|
|
63
|
-
**/
|
|
64
|
-
createContext?: AWSLambdaCreateContextFn<TRouter, TEvent>;
|
|
65
|
-
}
|
|
66
|
-
);
|
|
58
|
+
CreateContextCallback<
|
|
59
|
+
inferRouterContext<AnyRouter>,
|
|
60
|
+
AWSLambdaCreateContextFn<TRouter, TEvent>
|
|
61
|
+
>;
|
|
67
62
|
|
|
68
63
|
export function isPayloadV1(
|
|
69
64
|
event: APIGatewayEvent,
|
|
@@ -162,3 +157,14 @@ export type APIGatewayPayloadFormatVersion =
|
|
|
162
157
|
export const UNKNOWN_PAYLOAD_FORMAT_VERSION_ERROR_MESSAGE =
|
|
163
158
|
'Custom payload format version not handled by this adapter. Please use either 1.0 or 2.0. More information here' +
|
|
164
159
|
'https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-lambda.html';
|
|
160
|
+
|
|
161
|
+
export function lambdaEventToHTTPBody(event: APIGatewayEvent) {
|
|
162
|
+
let body: string | null | undefined;
|
|
163
|
+
if (event.body && event.isBase64Encoded) {
|
|
164
|
+
body = Buffer.from(event.body, 'base64').toString('utf8');
|
|
165
|
+
} else {
|
|
166
|
+
body = event.body;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return body;
|
|
170
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { TRPCError } from '../../@trpc/server';
|
|
2
|
+
import type { BaseContentTypeHandler } from '../../@trpc/server/http';
|
|
3
|
+
|
|
4
|
+
export function selectContentHandlerOrUnsupportedMediaType<
|
|
5
|
+
THandlerOpts,
|
|
6
|
+
THandler extends BaseContentTypeHandler<THandlerOpts>,
|
|
7
|
+
>(handlers: THandler[], opts: THandlerOpts) {
|
|
8
|
+
const handler = handlers.find((handler) => handler.isMatch(opts));
|
|
9
|
+
if (!handler) {
|
|
10
|
+
return [
|
|
11
|
+
undefined,
|
|
12
|
+
new TRPCError({
|
|
13
|
+
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
14
|
+
message:
|
|
15
|
+
'Invalid Content-Type header. This request may not be supported by your tRPC Adapter, or possibly by tRPC at all',
|
|
16
|
+
}),
|
|
17
|
+
] as const;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return [handler] as const;
|
|
21
|
+
}
|
package/src/adapters/express.ts
CHANGED
|
@@ -27,12 +27,7 @@ export function createExpressMiddleware<TRouter extends AnyRouter>(
|
|
|
27
27
|
const endpoint = req.path.slice(1);
|
|
28
28
|
|
|
29
29
|
await nodeHTTPRequestHandler({
|
|
30
|
-
|
|
31
|
-
...(opts as NodeHTTPHandlerOptions<
|
|
32
|
-
AnyRouter,
|
|
33
|
-
express.Request,
|
|
34
|
-
express.Response
|
|
35
|
-
>),
|
|
30
|
+
...opts,
|
|
36
31
|
req,
|
|
37
32
|
res,
|
|
38
33
|
path: endpoint,
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// @trpc/server
|
|
2
|
+
import type { FastifyReply, FastifyRequest } from 'fastify';
|
|
3
|
+
import { TRPCError } from '../../../../@trpc/server';
|
|
4
|
+
import type {
|
|
5
|
+
AnyRouter,
|
|
6
|
+
CombinedDataTransformer,
|
|
7
|
+
} from '../../../../@trpc/server';
|
|
8
|
+
import type { BaseContentTypeHandler } from '../../../../@trpc/server/http';
|
|
9
|
+
import type { FastifyRequestHandlerOptions } from '../../types';
|
|
10
|
+
|
|
11
|
+
export interface FastifyHTTPContentTypeHandler<
|
|
12
|
+
TRouter extends AnyRouter,
|
|
13
|
+
TRequest extends FastifyRequest,
|
|
14
|
+
TResponse extends FastifyReply,
|
|
15
|
+
> extends BaseContentTypeHandler<
|
|
16
|
+
FastifyRequestHandlerOptions<TRouter, TRequest, TResponse>
|
|
17
|
+
> {}
|
|
18
|
+
|
|
19
|
+
export const getFastifyHTTPJSONContentTypeHandler: <
|
|
20
|
+
TRouter extends AnyRouter,
|
|
21
|
+
TRequest extends FastifyRequest,
|
|
22
|
+
TResponse extends FastifyReply,
|
|
23
|
+
>() => FastifyHTTPContentTypeHandler<TRouter, TRequest, TResponse> = () => ({
|
|
24
|
+
name: 'fastify-json',
|
|
25
|
+
isMatch(opts) {
|
|
26
|
+
return !!opts.req.headers['content-type']?.startsWith('application/json');
|
|
27
|
+
},
|
|
28
|
+
getInputs: async (opts, info) => {
|
|
29
|
+
async function getRawProcedureInputOrThrow() {
|
|
30
|
+
const { req } = opts;
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
if (req.method === 'GET') {
|
|
34
|
+
const query = opts.req.query
|
|
35
|
+
? new URLSearchParams(opts.req.query as any)
|
|
36
|
+
: new URLSearchParams(opts.req.url.split('?')[1]);
|
|
37
|
+
|
|
38
|
+
const input = query.get('input');
|
|
39
|
+
if (!input) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return JSON.parse(input);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const body = opts.req.body ?? 'null';
|
|
47
|
+
if (typeof body === 'string') {
|
|
48
|
+
// A mutation with no inputs will have req.body === ''
|
|
49
|
+
return body.length === 0 ? undefined : JSON.parse(body);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return body;
|
|
53
|
+
} catch (cause) {
|
|
54
|
+
throw new TRPCError({
|
|
55
|
+
code: 'PARSE_ERROR',
|
|
56
|
+
cause,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const deserializeInputValue = (
|
|
62
|
+
rawValue: unknown,
|
|
63
|
+
transformer: CombinedDataTransformer,
|
|
64
|
+
) => {
|
|
65
|
+
return typeof rawValue !== 'undefined'
|
|
66
|
+
? transformer.input.deserialize(rawValue)
|
|
67
|
+
: rawValue;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const rawInput = await getRawProcedureInputOrThrow();
|
|
71
|
+
if (rawInput === undefined) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const transformer = opts.router._def._config.transformer;
|
|
76
|
+
|
|
77
|
+
if (!info.isBatchCall) {
|
|
78
|
+
return deserializeInputValue(rawInput, transformer);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* istanbul ignore if */
|
|
82
|
+
if (
|
|
83
|
+
rawInput == null ||
|
|
84
|
+
typeof rawInput !== 'object' ||
|
|
85
|
+
Array.isArray(rawInput)
|
|
86
|
+
) {
|
|
87
|
+
throw new TRPCError({
|
|
88
|
+
code: 'BAD_REQUEST',
|
|
89
|
+
message: '"input" needs to be an object when doing a batch call',
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const rawValue = rawInput[info.batch];
|
|
94
|
+
|
|
95
|
+
return deserializeInputValue(rawValue, transformer);
|
|
96
|
+
},
|
|
97
|
+
});
|
|
@@ -7,12 +7,11 @@
|
|
|
7
7
|
* import type { HTTPBaseHandlerOptions } from '@trpc/server/http'
|
|
8
8
|
* ```
|
|
9
9
|
*/
|
|
10
|
-
import { Readable } from '
|
|
10
|
+
import { Readable } from 'stream';
|
|
11
11
|
import type { FastifyReply, FastifyRequest } from 'fastify';
|
|
12
12
|
// @trpc/server
|
|
13
13
|
import type { AnyRouter } from '../../@trpc/server';
|
|
14
14
|
import type {
|
|
15
|
-
HTTPBaseHandlerOptions,
|
|
16
15
|
HTTPRequest,
|
|
17
16
|
HTTPResponse,
|
|
18
17
|
ResolveHTTPRequestOptionsContextFn,
|
|
@@ -22,24 +21,9 @@ import {
|
|
|
22
21
|
getBatchStreamFormatter,
|
|
23
22
|
resolveHTTPResponse,
|
|
24
23
|
} from '../../@trpc/server/http';
|
|
25
|
-
import
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
TRouter extends AnyRouter,
|
|
29
|
-
TRequest extends FastifyRequest,
|
|
30
|
-
TResponse extends FastifyReply,
|
|
31
|
-
> = HTTPBaseHandlerOptions<TRouter, TRequest> &
|
|
32
|
-
NodeHTTPCreateContextOption<TRouter, TRequest, TResponse>;
|
|
33
|
-
|
|
34
|
-
type FastifyRequestHandlerOptions<
|
|
35
|
-
TRouter extends AnyRouter,
|
|
36
|
-
TRequest extends FastifyRequest,
|
|
37
|
-
TResponse extends FastifyReply,
|
|
38
|
-
> = FastifyHandlerOptions<TRouter, TRequest, TResponse> & {
|
|
39
|
-
req: TRequest;
|
|
40
|
-
res: TResponse;
|
|
41
|
-
path: string;
|
|
42
|
-
};
|
|
24
|
+
import { selectContentHandlerOrUnsupportedMediaType } from '../content-handlers/selectContentHandlerOrUnsupportedMediaType';
|
|
25
|
+
import { getFastifyHTTPJSONContentTypeHandler } from './content-type/json';
|
|
26
|
+
import type { FastifyRequestHandlerOptions } from './types';
|
|
43
27
|
|
|
44
28
|
export async function fastifyRequestHandler<
|
|
45
29
|
TRouter extends AnyRouter,
|
|
@@ -63,7 +47,6 @@ export async function fastifyRequestHandler<
|
|
|
63
47
|
query,
|
|
64
48
|
method: opts.req.method,
|
|
65
49
|
headers: opts.req.headers,
|
|
66
|
-
body: opts.req.body ?? 'null',
|
|
67
50
|
};
|
|
68
51
|
|
|
69
52
|
let resolve: (value: FastifyReply) => void;
|
|
@@ -108,10 +91,21 @@ export async function fastifyRequestHandler<
|
|
|
108
91
|
}
|
|
109
92
|
};
|
|
110
93
|
|
|
94
|
+
const [contentTypeHandler, unsupportedMediaTypeError] =
|
|
95
|
+
selectContentHandlerOrUnsupportedMediaType(
|
|
96
|
+
[getFastifyHTTPJSONContentTypeHandler<TRouter, TRequest, TResponse>()],
|
|
97
|
+
opts,
|
|
98
|
+
);
|
|
99
|
+
|
|
111
100
|
resolveHTTPResponse({
|
|
112
101
|
...opts,
|
|
113
102
|
req,
|
|
103
|
+
error: unsupportedMediaTypeError,
|
|
104
|
+
async getInput(info) {
|
|
105
|
+
return await contentTypeHandler?.getInputs(opts, info);
|
|
106
|
+
},
|
|
114
107
|
createContext,
|
|
108
|
+
|
|
115
109
|
onError(o) {
|
|
116
110
|
opts?.onError?.({ ...o, req: opts.req });
|
|
117
111
|
},
|
|
@@ -9,13 +9,13 @@
|
|
|
9
9
|
*/
|
|
10
10
|
/// <reference types="@fastify/websocket" />
|
|
11
11
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
|
|
12
|
-
import type { FastifyHandlerOptions } from '.';
|
|
13
12
|
// @trpc/server
|
|
14
13
|
import type { AnyRouter } from '../../@trpc/server';
|
|
15
14
|
import type { NodeHTTPCreateContextFnOptions } from '../node-http';
|
|
16
15
|
import type { WSSHandlerOptions } from '../ws';
|
|
17
16
|
import { getWSConnectionHandler } from '../ws';
|
|
18
17
|
import { fastifyRequestHandler } from './fastifyRequestHandler';
|
|
18
|
+
import type { FastifyHandlerOptions } from './types';
|
|
19
19
|
|
|
20
20
|
export interface FastifyTRPCPluginOptions<TRouter extends AnyRouter> {
|
|
21
21
|
prefix?: string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { FastifyReply, FastifyRequest } from 'fastify';
|
|
2
|
+
// @trpc/server
|
|
3
|
+
import type { AnyRouter } from '../../@trpc/server';
|
|
4
|
+
import type { HTTPBaseHandlerOptions } from '../../@trpc/server/http';
|
|
5
|
+
import type { NodeHTTPConditionCreateContextOption } from '../node-http';
|
|
6
|
+
|
|
7
|
+
export type FastifyHandlerOptions<
|
|
8
|
+
TRouter extends AnyRouter,
|
|
9
|
+
TRequest extends FastifyRequest,
|
|
10
|
+
TResponse extends FastifyReply,
|
|
11
|
+
> = HTTPBaseHandlerOptions<TRouter, TRequest> &
|
|
12
|
+
NodeHTTPConditionCreateContextOption<TRouter, TRequest, TResponse>;
|
|
13
|
+
|
|
14
|
+
export type FastifyRequestHandlerOptions<
|
|
15
|
+
TRouter extends AnyRouter,
|
|
16
|
+
TRequest extends FastifyRequest,
|
|
17
|
+
TResponse extends FastifyReply,
|
|
18
|
+
> = FastifyHandlerOptions<TRouter, TRequest, TResponse> & {
|
|
19
|
+
req: TRequest;
|
|
20
|
+
res: TResponse;
|
|
21
|
+
path: string;
|
|
22
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// @trpc/server
|
|
2
|
+
import { TRPCError } from '../../../../@trpc/server';
|
|
3
|
+
import type {
|
|
4
|
+
AnyRouter,
|
|
5
|
+
CombinedDataTransformer,
|
|
6
|
+
} from '../../../../@trpc/server';
|
|
7
|
+
import type { BaseContentTypeHandler } from '../../../../@trpc/server/http';
|
|
8
|
+
import type { FetchHandlerRequestOptions } from '../../types';
|
|
9
|
+
|
|
10
|
+
export interface FetchHTTPContentTypeHandler<TRouter extends AnyRouter>
|
|
11
|
+
extends BaseContentTypeHandler<
|
|
12
|
+
FetchHandlerRequestOptions<TRouter> & {
|
|
13
|
+
url: URL;
|
|
14
|
+
}
|
|
15
|
+
> {}
|
|
16
|
+
|
|
17
|
+
export const getFetchHTTPJSONContentTypeHandler: <
|
|
18
|
+
TRouter extends AnyRouter,
|
|
19
|
+
>() => FetchHTTPContentTypeHandler<TRouter> = () => ({
|
|
20
|
+
name: 'fetch-json',
|
|
21
|
+
isMatch(opts) {
|
|
22
|
+
return !!opts.req.headers
|
|
23
|
+
.get('content-type')
|
|
24
|
+
?.startsWith('application/json');
|
|
25
|
+
},
|
|
26
|
+
getInputs: async (opts, info) => {
|
|
27
|
+
async function getRawProcedureInputOrThrow() {
|
|
28
|
+
const { req } = opts;
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
if (req.method === 'GET') {
|
|
32
|
+
const input = opts.url.searchParams.get('input');
|
|
33
|
+
if (!input) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return JSON.parse(input);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const body = opts.req.headers
|
|
41
|
+
.get('content-type')
|
|
42
|
+
?.startsWith('application/json')
|
|
43
|
+
? await opts.req.text()
|
|
44
|
+
: '';
|
|
45
|
+
|
|
46
|
+
if (typeof body === 'string') {
|
|
47
|
+
// A mutation with no inputs will have req.body === ''
|
|
48
|
+
return body.length === 0 ? undefined : JSON.parse(body);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return body;
|
|
52
|
+
} catch (cause) {
|
|
53
|
+
throw new TRPCError({
|
|
54
|
+
code: 'PARSE_ERROR',
|
|
55
|
+
cause,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const deserializeInputValue = (
|
|
61
|
+
rawValue: unknown,
|
|
62
|
+
transformer: CombinedDataTransformer,
|
|
63
|
+
) => {
|
|
64
|
+
return typeof rawValue !== 'undefined'
|
|
65
|
+
? transformer.input.deserialize(rawValue)
|
|
66
|
+
: rawValue;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const rawInput = await getRawProcedureInputOrThrow();
|
|
70
|
+
if (rawInput === undefined) {
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const transformer = opts.router._def._config.transformer;
|
|
75
|
+
|
|
76
|
+
if (!info.isBatchCall) {
|
|
77
|
+
return deserializeInputValue(rawInput, transformer);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* istanbul ignore if */
|
|
81
|
+
if (
|
|
82
|
+
rawInput == null ||
|
|
83
|
+
typeof rawInput !== 'object' ||
|
|
84
|
+
Array.isArray(rawInput)
|
|
85
|
+
) {
|
|
86
|
+
throw new TRPCError({
|
|
87
|
+
code: 'BAD_REQUEST',
|
|
88
|
+
message: '"input" needs to be an object when doing a batch call',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const rawValue = rawInput[info.batch];
|
|
93
|
+
|
|
94
|
+
return deserializeInputValue(rawValue, transformer);
|
|
95
|
+
},
|
|
96
|
+
});
|
|
@@ -21,14 +21,10 @@ import {
|
|
|
21
21
|
resolveHTTPResponse,
|
|
22
22
|
toURL,
|
|
23
23
|
} from '../../@trpc/server/http';
|
|
24
|
+
import { selectContentHandlerOrUnsupportedMediaType } from '../content-handlers/selectContentHandlerOrUnsupportedMediaType';
|
|
25
|
+
import { getFetchHTTPJSONContentTypeHandler } from './content-type/json';
|
|
24
26
|
import type { FetchHandlerOptions } from './types';
|
|
25
27
|
|
|
26
|
-
export type FetchHandlerRequestOptions<TRouter extends AnyRouter> =
|
|
27
|
-
FetchHandlerOptions<TRouter> & {
|
|
28
|
-
req: Request;
|
|
29
|
-
endpoint: string;
|
|
30
|
-
};
|
|
31
|
-
|
|
32
28
|
const trimSlashes = (path: string): string => {
|
|
33
29
|
path = path.startsWith('/') ? path.slice(1) : path;
|
|
34
30
|
path = path.endsWith('/') ? path.slice(0, -1) : path;
|
|
@@ -37,7 +33,7 @@ const trimSlashes = (path: string): string => {
|
|
|
37
33
|
};
|
|
38
34
|
|
|
39
35
|
export async function fetchRequestHandler<TRouter extends AnyRouter>(
|
|
40
|
-
opts:
|
|
36
|
+
opts: FetchHandlerOptions<TRouter>,
|
|
41
37
|
): Promise<Response> {
|
|
42
38
|
const resHeaders = new Headers();
|
|
43
39
|
|
|
@@ -57,9 +53,6 @@ export async function fetchRequestHandler<TRouter extends AnyRouter>(
|
|
|
57
53
|
query: url.searchParams,
|
|
58
54
|
method: opts.req.method,
|
|
59
55
|
headers: Object.fromEntries(opts.req.headers),
|
|
60
|
-
body: opts.req.headers.get('content-type')?.startsWith('application/json')
|
|
61
|
-
? await opts.req.text()
|
|
62
|
-
: '',
|
|
63
56
|
};
|
|
64
57
|
|
|
65
58
|
let resolve: (value: Response) => void;
|
|
@@ -117,11 +110,30 @@ export async function fetchRequestHandler<TRouter extends AnyRouter>(
|
|
|
117
110
|
}
|
|
118
111
|
};
|
|
119
112
|
|
|
113
|
+
const [contentTypeHandler, unsupportedMediaTypeError] =
|
|
114
|
+
selectContentHandlerOrUnsupportedMediaType(
|
|
115
|
+
[getFetchHTTPJSONContentTypeHandler<TRouter>()],
|
|
116
|
+
{
|
|
117
|
+
...opts,
|
|
118
|
+
url,
|
|
119
|
+
},
|
|
120
|
+
);
|
|
121
|
+
|
|
120
122
|
resolveHTTPResponse({
|
|
121
123
|
...opts,
|
|
122
124
|
req,
|
|
123
125
|
createContext,
|
|
124
126
|
path,
|
|
127
|
+
error: unsupportedMediaTypeError,
|
|
128
|
+
async getInput(info) {
|
|
129
|
+
return await contentTypeHandler?.getInputs(
|
|
130
|
+
{
|
|
131
|
+
...opts,
|
|
132
|
+
url,
|
|
133
|
+
},
|
|
134
|
+
info,
|
|
135
|
+
);
|
|
136
|
+
},
|
|
125
137
|
onError(o) {
|
|
126
138
|
opts?.onError?.({ ...o, req: opts.req });
|
|
127
139
|
},
|
|
@@ -8,7 +8,12 @@
|
|
|
8
8
|
* ```
|
|
9
9
|
*/
|
|
10
10
|
// @trpc/server
|
|
11
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
AnyRouter,
|
|
13
|
+
CreateContextCallback,
|
|
14
|
+
inferRouterContext,
|
|
15
|
+
WrapCreateContext,
|
|
16
|
+
} from '../../@trpc/server';
|
|
12
17
|
// @trpc/server/http
|
|
13
18
|
import type {
|
|
14
19
|
HTTPBaseHandlerOptions,
|
|
@@ -26,19 +31,21 @@ export type FetchCreateContextFn<TRouter extends AnyRouter> = (
|
|
|
26
31
|
) => inferRouterContext<TRouter> | Promise<inferRouterContext<TRouter>>;
|
|
27
32
|
|
|
28
33
|
export type FetchCreateContextOption<TRouter extends AnyRouter> =
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
**/
|
|
34
|
-
createContext?: FetchCreateContextFn<TRouter>;
|
|
35
|
-
}
|
|
36
|
-
: {
|
|
37
|
-
/**
|
|
38
|
-
* @link https://trpc.io/docs/v11/context
|
|
39
|
-
**/
|
|
40
|
-
createContext: FetchCreateContextFn<TRouter>;
|
|
41
|
-
};
|
|
34
|
+
CreateContextCallback<
|
|
35
|
+
inferRouterContext<TRouter>,
|
|
36
|
+
FetchCreateContextFn<TRouter>
|
|
37
|
+
>;
|
|
42
38
|
|
|
43
39
|
export type FetchHandlerOptions<TRouter extends AnyRouter> =
|
|
44
|
-
FetchCreateContextOption<TRouter> &
|
|
40
|
+
FetchCreateContextOption<TRouter> &
|
|
41
|
+
HTTPBaseHandlerOptions<TRouter, Request> & {
|
|
42
|
+
req: Request;
|
|
43
|
+
endpoint: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type FetchHandlerRequestOptions<TRouter extends AnyRouter> =
|
|
47
|
+
HTTPBaseHandlerOptions<TRouter, Request> &
|
|
48
|
+
WrapCreateContext<FetchCreateContextFn<TRouter>> & {
|
|
49
|
+
req: Request;
|
|
50
|
+
endpoint: string;
|
|
51
|
+
};
|