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