@trpc/server 10.28.2 → 10.29.1
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/adapters/aws-lambda/index.js +1 -1
- package/dist/adapters/aws-lambda/index.mjs +1 -1
- package/dist/adapters/express.js +5 -4
- package/dist/adapters/express.mjs +5 -4
- package/dist/adapters/fastify/fastifyRequestHandler.d.ts +1 -1
- package/dist/adapters/fastify/fastifyRequestHandler.d.ts.map +1 -1
- package/dist/adapters/fastify/index.js +51 -15
- package/dist/adapters/fastify/index.mjs +51 -15
- package/dist/adapters/fetch/fetchRequestHandler.d.ts.map +1 -1
- package/dist/adapters/fetch/index.js +67 -20
- package/dist/adapters/fetch/index.mjs +67 -20
- package/dist/adapters/next.js +3 -2
- package/dist/adapters/next.mjs +3 -2
- package/dist/adapters/node-http/content-type/form-data/index.js +19 -46
- package/dist/adapters/node-http/content-type/form-data/index.mjs +19 -40
- package/dist/adapters/node-http/content-type/form-data/streamSlice.d.ts +7 -3
- package/dist/adapters/node-http/content-type/form-data/streamSlice.d.ts.map +1 -1
- package/dist/adapters/node-http/index.js +5 -4
- package/dist/adapters/node-http/index.mjs +5 -4
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +1 -1
- package/dist/adapters/node-http/types.d.ts +11 -1
- package/dist/adapters/node-http/types.d.ts.map +1 -1
- package/dist/adapters/standalone.js +5 -4
- package/dist/adapters/standalone.mjs +5 -4
- package/dist/batchStreamFormatter-2c1405a1.js +31 -0
- package/dist/batchStreamFormatter-93cdcdd4.js +32 -0
- package/dist/batchStreamFormatter-fc1ffb26.mjs +30 -0
- package/dist/http/batchStreamFormatter.d.ts +24 -0
- package/dist/http/batchStreamFormatter.d.ts.map +1 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +3 -1
- package/dist/http/index.mjs +2 -1
- package/dist/http/internals/types.d.ts +7 -0
- package/dist/http/internals/types.d.ts.map +1 -1
- package/dist/http/resolveHTTPResponse.d.ts +37 -2
- package/dist/http/resolveHTTPResponse.d.ts.map +1 -1
- package/dist/{nodeHTTPRequestHandler-5bbf93f1.js → nodeHTTPRequestHandler-071d36b5.js} +44 -13
- package/dist/{nodeHTTPRequestHandler-bd47641d.js → nodeHTTPRequestHandler-51d58a23.js} +47 -12
- package/dist/{nodeHTTPRequestHandler-0f979796.mjs → nodeHTTPRequestHandler-bb12529f.mjs} +44 -13
- package/dist/resolveHTTPResponse-1f03fdfd.js +284 -0
- package/dist/resolveHTTPResponse-dd3677b3.mjs +282 -0
- package/dist/resolveHTTPResponse-e0047ea2.js +256 -0
- package/package.json +4 -4
- package/src/adapters/fastify/fastifyRequestHandler.ts +65 -17
- package/src/adapters/fetch/fetchRequestHandler.ts +73 -25
- package/src/adapters/node-http/content-type/form-data/streamSlice.ts +19 -21
- package/src/adapters/node-http/nodeHTTPRequestHandler.ts +53 -12
- package/src/adapters/node-http/types.ts +11 -1
- package/src/http/batchStreamFormatter.ts +29 -0
- package/src/http/index.ts +1 -0
- package/src/http/internals/types.ts +8 -0
- package/src/http/resolveHTTPResponse.ts +339 -124
- package/dist/resolveHTTPResponse-4e576698.mjs +0 -174
- package/dist/resolveHTTPResponse-9523b4e3.js +0 -176
- package/dist/resolveHTTPResponse-ba557d3e.js +0 -166
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format a batch response as a line-delimited JSON stream
|
|
3
|
+
* that the `unstable_httpBatchStreamLink` can parse:
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* const formatter = getBatchStreamFormatter();
|
|
8
|
+
* res.send(formatter(1, 'response #2'));
|
|
9
|
+
* res.send(formatter(0, 'response #1'));
|
|
10
|
+
* res.send(formatter.end());
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* Expected format:
|
|
14
|
+
* ```json
|
|
15
|
+
* {"1":"response #2"
|
|
16
|
+
* ,"0":"response #1"
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function getBatchStreamFormatter() {
|
|
21
|
+
let first = true;
|
|
22
|
+
function format(index: number, string: string) {
|
|
23
|
+
const prefix = first ? '{' : ',';
|
|
24
|
+
first = false;
|
|
25
|
+
return `${prefix}"${index}":${string}\n`;
|
|
26
|
+
}
|
|
27
|
+
format.end = () => '}';
|
|
28
|
+
return format;
|
|
29
|
+
}
|
package/src/http/index.ts
CHANGED
|
@@ -17,6 +17,8 @@ export interface HTTPResponse {
|
|
|
17
17
|
body?: string;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
export type ResponseChunk = [procedureIndex: number, responseBody: string];
|
|
21
|
+
|
|
20
22
|
/**
|
|
21
23
|
* @internal
|
|
22
24
|
*/
|
|
@@ -29,4 +31,10 @@ export type ResponseMetaFn<TRouter extends AnyRouter> = (opts: {
|
|
|
29
31
|
paths?: string[];
|
|
30
32
|
type: ProcedureType | 'unknown';
|
|
31
33
|
errors: TRPCError[];
|
|
34
|
+
/**
|
|
35
|
+
* `true` if the `ResponseMeta` are being
|
|
36
|
+
* generated without knowing the response data
|
|
37
|
+
* (e.g. for streaming requests).
|
|
38
|
+
*/
|
|
39
|
+
eagerGeneration?: boolean;
|
|
32
40
|
}) => ResponseMeta;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
1
|
import {
|
|
3
2
|
AnyRouter,
|
|
4
3
|
callProcedure,
|
|
@@ -16,7 +15,7 @@ import {
|
|
|
16
15
|
getJsonContentTypeInputs,
|
|
17
16
|
} from './contentType';
|
|
18
17
|
import { getHTTPStatusCode } from './getHTTPStatusCode';
|
|
19
|
-
import { HTTPHeaders, HTTPResponse } from './internals/types';
|
|
18
|
+
import { HTTPHeaders, HTTPResponse, ResponseChunk } from './internals/types';
|
|
20
19
|
import { HTTPBaseHandlerOptions, HTTPRequest } from './types';
|
|
21
20
|
|
|
22
21
|
const HTTP_METHOD_PROCEDURE_TYPE_MAP: Record<
|
|
@@ -31,6 +30,12 @@ const fallbackContentTypeHandler = {
|
|
|
31
30
|
getInputs: getJsonContentTypeInputs,
|
|
32
31
|
};
|
|
33
32
|
|
|
33
|
+
type PartialBy<TBaseType, TKey extends keyof TBaseType> = Omit<
|
|
34
|
+
TBaseType,
|
|
35
|
+
TKey
|
|
36
|
+
> &
|
|
37
|
+
Partial<Pick<TBaseType, TKey>>;
|
|
38
|
+
|
|
34
39
|
interface ResolveHTTPRequestOptions<
|
|
35
40
|
TRouter extends AnyRouter,
|
|
36
41
|
TRequest extends HTTPRequest,
|
|
@@ -41,72 +46,245 @@ interface ResolveHTTPRequestOptions<
|
|
|
41
46
|
error?: Maybe<TRPCError>;
|
|
42
47
|
contentTypeHandler?: BaseContentTypeHandler<any>;
|
|
43
48
|
preprocessedBody?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Called as soon as the response head is known.
|
|
51
|
+
* When streaming, headers will have been generated
|
|
52
|
+
* **without** knowing the response body.
|
|
53
|
+
*
|
|
54
|
+
* Without this callback, streaming is disabled.
|
|
55
|
+
*/
|
|
56
|
+
unstable_onHead: (
|
|
57
|
+
headResponse: Omit<HTTPResponse, 'body'>,
|
|
58
|
+
isStreaming: boolean,
|
|
59
|
+
) => void;
|
|
60
|
+
/**
|
|
61
|
+
* Called for every procedure with `[index, result]`.
|
|
62
|
+
*
|
|
63
|
+
* Will be called a single time with `index = -1` if
|
|
64
|
+
* - response is an error
|
|
65
|
+
* - response is empty (HEAD request)
|
|
66
|
+
*
|
|
67
|
+
* Without this callback, streaming is disabled.
|
|
68
|
+
*/
|
|
69
|
+
unstable_onChunk: (chunk: ResponseChunk) => void;
|
|
44
70
|
}
|
|
45
71
|
|
|
46
|
-
|
|
72
|
+
function initResponse<
|
|
47
73
|
TRouter extends AnyRouter,
|
|
48
74
|
TRequest extends HTTPRequest,
|
|
49
|
-
>(
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
75
|
+
>(initOpts: {
|
|
76
|
+
ctx: inferRouterContext<TRouter> | undefined;
|
|
77
|
+
paths: string[] | undefined;
|
|
78
|
+
type: ProcedureType | 'unknown';
|
|
79
|
+
responseMeta?: HTTPBaseHandlerOptions<TRouter, TRequest>['responseMeta'];
|
|
80
|
+
untransformedJSON?:
|
|
81
|
+
| TRPCResponse<unknown, inferRouterError<TRouter>>
|
|
82
|
+
| TRPCResponse<unknown, inferRouterError<TRouter>>[]
|
|
83
|
+
| undefined;
|
|
84
|
+
errors?: TRPCError[];
|
|
85
|
+
}): HTTPResponse {
|
|
86
|
+
const {
|
|
87
|
+
ctx,
|
|
88
|
+
paths,
|
|
89
|
+
type,
|
|
90
|
+
responseMeta,
|
|
91
|
+
untransformedJSON,
|
|
92
|
+
errors = [],
|
|
93
|
+
} = initOpts;
|
|
53
94
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
95
|
+
let status = untransformedJSON ? getHTTPStatusCode(untransformedJSON) : 200;
|
|
96
|
+
const headers: HTTPHeaders = {
|
|
97
|
+
'Content-Type': 'application/json',
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const eagerGeneration = !untransformedJSON;
|
|
101
|
+
const data = eagerGeneration
|
|
102
|
+
? []
|
|
103
|
+
: Array.isArray(untransformedJSON)
|
|
104
|
+
? untransformedJSON
|
|
105
|
+
: [untransformedJSON];
|
|
106
|
+
|
|
107
|
+
const meta =
|
|
108
|
+
responseMeta?.({
|
|
109
|
+
ctx,
|
|
110
|
+
paths,
|
|
111
|
+
type,
|
|
112
|
+
data,
|
|
113
|
+
errors,
|
|
114
|
+
eagerGeneration,
|
|
115
|
+
}) ?? {};
|
|
116
|
+
|
|
117
|
+
for (const [key, value] of Object.entries(meta.headers ?? {})) {
|
|
118
|
+
headers[key] = value;
|
|
119
|
+
}
|
|
120
|
+
if (meta.status) {
|
|
121
|
+
status = meta.status;
|
|
60
122
|
}
|
|
61
|
-
const type =
|
|
62
|
-
HTTP_METHOD_PROCEDURE_TYPE_MAP[req.method] ?? ('unknown' as const);
|
|
63
|
-
let ctx: inferRouterContext<TRouter> | undefined = undefined;
|
|
64
|
-
let paths: string[] | undefined = undefined;
|
|
65
123
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
124
|
+
return {
|
|
125
|
+
status,
|
|
126
|
+
headers,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
async function inputToProcedureCall<
|
|
131
|
+
TRouter extends AnyRouter,
|
|
132
|
+
TRequest extends HTTPRequest,
|
|
133
|
+
>(procedureOpts: {
|
|
134
|
+
opts: Pick<
|
|
135
|
+
ResolveHTTPRequestOptions<TRouter, TRequest>,
|
|
136
|
+
'router' | 'onError' | 'req'
|
|
137
|
+
>;
|
|
138
|
+
ctx: inferRouterContext<TRouter> | undefined;
|
|
139
|
+
type: 'query' | 'mutation';
|
|
140
|
+
input: unknown;
|
|
141
|
+
path: string;
|
|
142
|
+
}): Promise<TRPCResponse<unknown, inferRouterError<TRouter>>> {
|
|
143
|
+
const { opts, ctx, type, input, path } = procedureOpts;
|
|
144
|
+
try {
|
|
145
|
+
const data = await callProcedure({
|
|
146
|
+
procedures: opts.router._def.procedures,
|
|
147
|
+
path,
|
|
148
|
+
rawInput: input,
|
|
149
|
+
ctx,
|
|
150
|
+
type,
|
|
151
|
+
});
|
|
152
|
+
return {
|
|
153
|
+
result: {
|
|
154
|
+
data,
|
|
155
|
+
},
|
|
77
156
|
};
|
|
157
|
+
} catch (cause) {
|
|
158
|
+
const error = getTRPCErrorFromUnknown(cause);
|
|
78
159
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
160
|
+
opts.onError?.({ error, path, input, ctx, type: type, req: opts.req });
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
error: getErrorShape({
|
|
164
|
+
config: opts.router._def._config,
|
|
165
|
+
error,
|
|
83
166
|
type,
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
167
|
+
path,
|
|
168
|
+
input,
|
|
169
|
+
ctx,
|
|
170
|
+
}),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
}
|
|
89
174
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
175
|
+
function caughtErrorToData<
|
|
176
|
+
TRouter extends AnyRouter,
|
|
177
|
+
TRequest extends HTTPRequest,
|
|
178
|
+
>(
|
|
179
|
+
cause: unknown,
|
|
180
|
+
errorOpts: {
|
|
181
|
+
opts: Pick<
|
|
182
|
+
ResolveHTTPRequestOptions<TRouter, TRequest>,
|
|
183
|
+
'router' | 'onError' | 'req'
|
|
184
|
+
>;
|
|
185
|
+
ctx: inferRouterContext<TRouter> | undefined;
|
|
186
|
+
type: ProcedureType | 'unknown';
|
|
187
|
+
path?: string;
|
|
188
|
+
input?: unknown;
|
|
189
|
+
},
|
|
190
|
+
) {
|
|
191
|
+
const { router, req, onError } = errorOpts.opts;
|
|
192
|
+
const error = getTRPCErrorFromUnknown(cause);
|
|
193
|
+
onError?.({
|
|
194
|
+
error,
|
|
195
|
+
path: errorOpts.path,
|
|
196
|
+
input: errorOpts.input,
|
|
197
|
+
ctx: errorOpts.ctx,
|
|
198
|
+
type: errorOpts.type,
|
|
199
|
+
req,
|
|
200
|
+
});
|
|
201
|
+
const untransformedJSON = {
|
|
202
|
+
error: getErrorShape({
|
|
203
|
+
config: router._def._config,
|
|
204
|
+
error,
|
|
205
|
+
type: errorOpts.type,
|
|
206
|
+
path: errorOpts.path,
|
|
207
|
+
input: errorOpts.input,
|
|
208
|
+
ctx: errorOpts.ctx,
|
|
209
|
+
}),
|
|
210
|
+
};
|
|
211
|
+
const transformedJSON = transformTRPCResponse(
|
|
212
|
+
router._def._config,
|
|
213
|
+
untransformedJSON,
|
|
214
|
+
);
|
|
215
|
+
const body = JSON.stringify(transformedJSON);
|
|
216
|
+
return {
|
|
217
|
+
error,
|
|
218
|
+
untransformedJSON,
|
|
219
|
+
body,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
96
222
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
223
|
+
/**
|
|
224
|
+
* Since `resolveHTTPResponse` is a public API (community adapters),
|
|
225
|
+
* let's give it a strong type signature to increase discoverability.
|
|
226
|
+
*/
|
|
101
227
|
|
|
102
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Non-streaming signature for `resolveHTTPResponse`:
|
|
230
|
+
* @param opts.unstable_onHead `undefined`
|
|
231
|
+
* @param opts.unstable_onChunk `undefined`
|
|
232
|
+
* @returns `Promise<HTTPResponse>`
|
|
233
|
+
*/
|
|
234
|
+
export async function resolveHTTPResponse<
|
|
235
|
+
TRouter extends AnyRouter,
|
|
236
|
+
TRequest extends HTTPRequest,
|
|
237
|
+
>(
|
|
238
|
+
opts: Omit<
|
|
239
|
+
ResolveHTTPRequestOptions<TRouter, TRequest>,
|
|
240
|
+
'unstable_onHead' | 'unstable_onChunk'
|
|
241
|
+
>,
|
|
242
|
+
): Promise<HTTPResponse>;
|
|
243
|
+
/**
|
|
244
|
+
* Streaming signature for `resolveHTTPResponse`:
|
|
245
|
+
* @param opts.unstable_onHead called as soon as the response head is known
|
|
246
|
+
* @param opts.unstable_onChunk called for every procedure with `[index, result]`
|
|
247
|
+
* @returns `Promise<void>` since the response is streamed
|
|
248
|
+
*/
|
|
249
|
+
export async function resolveHTTPResponse<
|
|
250
|
+
TRouter extends AnyRouter,
|
|
251
|
+
TRequest extends HTTPRequest,
|
|
252
|
+
>(opts: ResolveHTTPRequestOptions<TRouter, TRequest>): Promise<void>;
|
|
253
|
+
// implementation
|
|
254
|
+
export async function resolveHTTPResponse<
|
|
255
|
+
TRouter extends AnyRouter,
|
|
256
|
+
TRequest extends HTTPRequest,
|
|
257
|
+
>(
|
|
258
|
+
opts: PartialBy<
|
|
259
|
+
ResolveHTTPRequestOptions<TRouter, TRequest>,
|
|
260
|
+
'unstable_onHead' | 'unstable_onChunk'
|
|
261
|
+
>,
|
|
262
|
+
): Promise<HTTPResponse | void> {
|
|
263
|
+
const { router, req, unstable_onHead, unstable_onChunk } = opts;
|
|
103
264
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
265
|
+
if (req.method === 'HEAD') {
|
|
266
|
+
// can be used for lambda warmup
|
|
267
|
+
const headResponse: HTTPResponse = {
|
|
268
|
+
status: 204,
|
|
108
269
|
};
|
|
270
|
+
unstable_onHead?.(headResponse, false);
|
|
271
|
+
unstable_onChunk?.([-1, '']);
|
|
272
|
+
return headResponse;
|
|
109
273
|
}
|
|
274
|
+
const contentTypeHandler =
|
|
275
|
+
opts.contentTypeHandler ?? fallbackContentTypeHandler;
|
|
276
|
+
const batchingEnabled = opts.batching?.enabled ?? true;
|
|
277
|
+
const type =
|
|
278
|
+
HTTP_METHOD_PROCEDURE_TYPE_MAP[req.method] ?? ('unknown' as const);
|
|
279
|
+
let ctx: inferRouterContext<TRouter> | undefined = undefined;
|
|
280
|
+
let paths: string[] | undefined;
|
|
281
|
+
|
|
282
|
+
const isBatchCall = !!req.query.get('batch');
|
|
283
|
+
const isStreamCall =
|
|
284
|
+
isBatchCall &&
|
|
285
|
+
unstable_onHead &&
|
|
286
|
+
unstable_onChunk &&
|
|
287
|
+
req.headers['trpc-batch-mode'] === 'stream';
|
|
110
288
|
|
|
111
289
|
try {
|
|
112
290
|
if (opts.error) {
|
|
@@ -138,91 +316,128 @@ export async function resolveHTTPResponse<
|
|
|
138
316
|
|
|
139
317
|
paths = isBatchCall ? opts.path.split(',') : [opts.path];
|
|
140
318
|
ctx = await opts.createContext();
|
|
319
|
+
const promises = paths.map((path, index) =>
|
|
320
|
+
inputToProcedureCall({ opts, ctx, type, input: inputs[index], path }),
|
|
321
|
+
);
|
|
141
322
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
323
|
+
if (!isStreamCall) {
|
|
324
|
+
/**
|
|
325
|
+
* Non-streaming response:
|
|
326
|
+
* - await all responses in parallel, blocking on the slowest one
|
|
327
|
+
* - create headers with known response body
|
|
328
|
+
* - return a complete HTTPResponse
|
|
329
|
+
*/
|
|
145
330
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
result: {
|
|
189
|
-
data: obj.data,
|
|
190
|
-
},
|
|
191
|
-
};
|
|
192
|
-
}
|
|
331
|
+
const untransformedJSON = await Promise.all(promises);
|
|
332
|
+
const errors = untransformedJSON.flatMap((response) =>
|
|
333
|
+
'error' in response ? [response.error] : [],
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
const headResponse = initResponse({
|
|
337
|
+
ctx,
|
|
338
|
+
paths,
|
|
339
|
+
type,
|
|
340
|
+
responseMeta: opts.responseMeta,
|
|
341
|
+
untransformedJSON,
|
|
342
|
+
errors,
|
|
343
|
+
});
|
|
344
|
+
unstable_onHead?.(headResponse, false);
|
|
345
|
+
|
|
346
|
+
// return body stuff
|
|
347
|
+
const result = isBatchCall ? untransformedJSON : untransformedJSON[0]!; // eslint-disable-line @typescript-eslint/no-non-null-assertion -- `untransformedJSON` should be the length of `paths` which should be at least 1 otherwise there wouldn't be a request at all
|
|
348
|
+
const transformedJSON = transformTRPCResponse(
|
|
349
|
+
router._def._config,
|
|
350
|
+
result,
|
|
351
|
+
);
|
|
352
|
+
const body = JSON.stringify(transformedJSON);
|
|
353
|
+
unstable_onChunk?.([-1, body]);
|
|
354
|
+
|
|
355
|
+
return {
|
|
356
|
+
status: headResponse.status,
|
|
357
|
+
headers: headResponse.headers,
|
|
358
|
+
body,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* Streaming response:
|
|
364
|
+
* - block on none, call `onChunk` as soon as each response is ready
|
|
365
|
+
* - create headers with minimal data (cannot know the response body in advance)
|
|
366
|
+
* - return void
|
|
367
|
+
*/
|
|
368
|
+
const headResponse = initResponse({
|
|
369
|
+
ctx,
|
|
370
|
+
paths,
|
|
371
|
+
type,
|
|
372
|
+
responseMeta: opts.responseMeta,
|
|
193
373
|
});
|
|
374
|
+
unstable_onHead(headResponse, true);
|
|
375
|
+
|
|
376
|
+
const indexedPromises = new Map(
|
|
377
|
+
promises.map((promise, index) => [
|
|
378
|
+
index,
|
|
379
|
+
promise.then((r) => [index, r] as const),
|
|
380
|
+
]),
|
|
381
|
+
);
|
|
382
|
+
for (let i = 0; i < paths.length; i++) {
|
|
383
|
+
const [index, untransformedJSON] = await Promise.race(
|
|
384
|
+
indexedPromises.values(),
|
|
385
|
+
);
|
|
386
|
+
indexedPromises.delete(index);
|
|
387
|
+
|
|
388
|
+
try {
|
|
389
|
+
const transformedJSON = transformTRPCResponse(
|
|
390
|
+
router._def._config,
|
|
391
|
+
untransformedJSON,
|
|
392
|
+
);
|
|
393
|
+
const body = JSON.stringify(transformedJSON);
|
|
394
|
+
|
|
395
|
+
unstable_onChunk([index, body]);
|
|
396
|
+
} catch (cause) {
|
|
397
|
+
const path = paths[index];
|
|
398
|
+
const input = inputs[index];
|
|
399
|
+
const { body } = caughtErrorToData(cause, {
|
|
400
|
+
opts,
|
|
401
|
+
ctx,
|
|
402
|
+
type,
|
|
403
|
+
path,
|
|
404
|
+
input,
|
|
405
|
+
});
|
|
194
406
|
|
|
195
|
-
|
|
196
|
-
|
|
407
|
+
unstable_onChunk([index, body]);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return;
|
|
197
411
|
} catch (cause) {
|
|
198
412
|
// we get here if
|
|
199
413
|
// - batching is called when it's not enabled
|
|
200
414
|
// - `createContext()` throws
|
|
415
|
+
// - `router._def._config.transformer.output.serialize()` throws
|
|
201
416
|
// - post body is too large
|
|
202
417
|
// - input deserialization fails
|
|
203
418
|
// - `errorFormatter` return value is malformed
|
|
204
|
-
const error =
|
|
419
|
+
const { error, untransformedJSON, body } = caughtErrorToData(cause, {
|
|
420
|
+
opts,
|
|
421
|
+
ctx,
|
|
422
|
+
type,
|
|
423
|
+
});
|
|
205
424
|
|
|
206
|
-
|
|
207
|
-
error,
|
|
208
|
-
path: undefined,
|
|
209
|
-
input: undefined,
|
|
425
|
+
const headResponse = initResponse({
|
|
210
426
|
ctx,
|
|
211
|
-
|
|
212
|
-
|
|
427
|
+
paths,
|
|
428
|
+
type,
|
|
429
|
+
responseMeta: opts.responseMeta,
|
|
430
|
+
untransformedJSON,
|
|
431
|
+
errors: [error],
|
|
213
432
|
});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}),
|
|
224
|
-
},
|
|
225
|
-
[error],
|
|
226
|
-
);
|
|
433
|
+
unstable_onHead?.(headResponse, false);
|
|
434
|
+
|
|
435
|
+
unstable_onChunk?.([-1, body]);
|
|
436
|
+
|
|
437
|
+
return {
|
|
438
|
+
status: headResponse.status,
|
|
439
|
+
headers: headResponse.headers,
|
|
440
|
+
body,
|
|
441
|
+
};
|
|
227
442
|
}
|
|
228
443
|
}
|