@trpc/server 11.0.0-alpha-tmp-app-router-example.388 → 11.0.0-alpha-tmp-issues-5851-take-two.448
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 +1 -2
- package/dist/@trpc/server/http.d.ts.map +1 -1
- package/dist/@trpc/server/index.d.ts +1 -1
- package/dist/@trpc/server/index.d.ts.map +1 -1
- package/dist/@trpc/server/rpc.d.ts +1 -1
- package/dist/@trpc/server/rpc.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/getPlanner.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/getPlanner.js +19 -2
- package/dist/adapters/aws-lambda/getPlanner.mjs +19 -2
- package/dist/adapters/next-app-dir/nextAppDirCaller.d.ts.map +1 -1
- package/dist/adapters/next-app-dir/nextAppDirCaller.js +1 -1
- package/dist/adapters/next-app-dir/nextAppDirCaller.mjs +1 -1
- package/dist/adapters/next-app-dir/redirect.d.ts.map +1 -1
- package/dist/adapters/next.js +1 -1
- package/dist/adapters/next.mjs +1 -1
- package/dist/adapters/node-http/incomingMessageToRequest.d.ts +0 -1
- package/dist/adapters/node-http/incomingMessageToRequest.d.ts.map +1 -1
- package/dist/adapters/node-http/incomingMessageToRequest.js +3 -1
- package/dist/adapters/node-http/incomingMessageToRequest.mjs +3 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +1 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.js +30 -7
- package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +30 -7
- package/dist/adapters/node-http/types.d.ts +0 -1
- package/dist/adapters/node-http/types.d.ts.map +1 -1
- package/dist/adapters/standalone.d.ts +0 -1
- package/dist/adapters/standalone.d.ts.map +1 -1
- package/dist/adapters/ws.d.ts +3 -4
- package/dist/adapters/ws.d.ts.map +1 -1
- package/dist/adapters/ws.js +172 -114
- package/dist/adapters/ws.mjs +172 -114
- package/dist/bundle-analysis.json +236 -155
- package/dist/http.js +3 -0
- package/dist/http.mjs +1 -0
- package/dist/index.js +7 -5
- package/dist/index.mjs +3 -2
- package/dist/observable/observable.d.ts +1 -0
- package/dist/observable/observable.d.ts.map +1 -1
- package/dist/observable/observable.js +55 -0
- package/dist/observable/observable.mjs +55 -1
- package/dist/unstable-core-do-not-import/createProxy.d.ts +3 -3
- package/dist/unstable-core-do-not-import/createProxy.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/createProxy.js +15 -6
- package/dist/unstable-core-do-not-import/createProxy.mjs +15 -6
- package/dist/unstable-core-do-not-import/http/contentType.d.ts +7 -4
- package/dist/unstable-core-do-not-import/http/contentType.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/contentType.js +60 -17
- package/dist/unstable-core-do-not-import/http/contentType.mjs +61 -18
- package/dist/unstable-core-do-not-import/http/formDataToObject.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/http/formDataToObject.js +40 -0
- package/dist/unstable-core-do-not-import/http/formDataToObject.mjs +38 -0
- package/dist/unstable-core-do-not-import/http/getHTTPStatusCode.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/getHTTPStatusCode.js +4 -4
- package/dist/unstable-core-do-not-import/http/getHTTPStatusCode.mjs +4 -4
- package/dist/unstable-core-do-not-import/http/parseConnectionParams.d.ts +4 -0
- package/dist/unstable-core-do-not-import/http/parseConnectionParams.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/http/parseConnectionParams.js +42 -0
- package/dist/unstable-core-do-not-import/http/parseConnectionParams.mjs +39 -0
- package/dist/unstable-core-do-not-import/http/resolveResponse.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/resolveResponse.js +302 -149
- package/dist/unstable-core-do-not-import/http/resolveResponse.mjs +301 -148
- package/dist/unstable-core-do-not-import/http/types.d.ts +26 -2
- package/dist/unstable-core-do-not-import/http/types.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/initTRPC.d.ts +12 -12
- package/dist/unstable-core-do-not-import/initTRPC.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/middleware.d.ts +3 -3
- package/dist/unstable-core-do-not-import/middleware.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/procedureBuilder.d.ts +3 -1
- package/dist/unstable-core-do-not-import/procedureBuilder.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/rootConfig.d.ts +12 -0
- package/dist/unstable-core-do-not-import/rootConfig.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/router.d.ts +2 -2
- package/dist/unstable-core-do-not-import/router.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/router.js +7 -2
- package/dist/unstable-core-do-not-import/router.mjs +7 -2
- package/dist/unstable-core-do-not-import/rpc/envelopes.d.ts +7 -0
- package/dist/unstable-core-do-not-import/rpc/envelopes.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/rpc/index.d.ts +1 -1
- package/dist/unstable-core-do-not-import/rpc/index.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/stream/{stream.d.ts → jsonl.d.ts} +5 -5
- package/dist/unstable-core-do-not-import/stream/jsonl.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/{stream.js → jsonl.js} +148 -111
- package/dist/unstable-core-do-not-import/stream/{stream.mjs → jsonl.mjs} +147 -110
- package/dist/unstable-core-do-not-import/stream/sse.d.ts +86 -0
- package/dist/unstable-core-do-not-import/stream/sse.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/sse.js +178 -0
- package/dist/unstable-core-do-not-import/stream/sse.mjs +172 -0
- package/dist/unstable-core-do-not-import/stream/utils/createDeferred.d.ts +18 -0
- package/dist/unstable-core-do-not-import/stream/utils/createDeferred.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/utils/createDeferred.js +46 -0
- package/dist/unstable-core-do-not-import/stream/utils/createDeferred.mjs +43 -0
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts +10 -0
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.js +31 -0
- package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.mjs +29 -0
- package/dist/unstable-core-do-not-import/stream/utils/createServer.d.ts +7 -0
- package/dist/unstable-core-do-not-import/stream/utils/createServer.d.ts.map +1 -0
- package/dist/unstable-core-do-not-import/transformer.d.ts +5 -5
- package/dist/unstable-core-do-not-import/utils.d.ts +4 -0
- package/dist/unstable-core-do-not-import/utils.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/utils.js +4 -0
- package/dist/unstable-core-do-not-import/utils.mjs +4 -1
- package/dist/unstable-core-do-not-import.d.ts +5 -2
- package/dist/unstable-core-do-not-import.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import.js +19 -7
- package/dist/unstable-core-do-not-import.mjs +6 -3
- package/package.json +6 -6
- package/src/@trpc/server/http.ts +7 -2
- package/src/@trpc/server/index.ts +1 -0
- package/src/@trpc/server/rpc.ts +1 -0
- package/src/adapters/aws-lambda/getPlanner.ts +21 -2
- package/src/adapters/next-app-dir/nextAppDirCaller.ts +2 -1
- package/src/adapters/node-http/incomingMessageToRequest.ts +3 -2
- package/src/adapters/node-http/nodeHTTPRequestHandler.ts +32 -7
- package/src/adapters/ws.ts +193 -107
- package/src/observable/observable.ts +63 -0
- package/src/unstable-core-do-not-import/createProxy.ts +23 -8
- package/src/unstable-core-do-not-import/http/contentType.ts +83 -21
- package/src/{adapters/next-app-dir → unstable-core-do-not-import/http}/formDataToObject.ts +18 -10
- package/src/unstable-core-do-not-import/http/getHTTPStatusCode.ts +4 -7
- package/src/unstable-core-do-not-import/http/parseConnectionParams.ts +49 -0
- package/src/unstable-core-do-not-import/http/resolveResponse.ts +333 -164
- package/src/unstable-core-do-not-import/http/types.ts +31 -2
- package/src/unstable-core-do-not-import/procedureBuilder.ts +8 -1
- package/src/unstable-core-do-not-import/rootConfig.ts +12 -0
- package/src/unstable-core-do-not-import/router.ts +47 -35
- package/src/unstable-core-do-not-import/rpc/envelopes.ts +9 -0
- package/src/unstable-core-do-not-import/rpc/index.ts +1 -0
- package/src/unstable-core-do-not-import/stream/{stream.ts → jsonl.ts} +163 -110
- package/src/unstable-core-do-not-import/stream/sse.ts +288 -0
- package/src/unstable-core-do-not-import/stream/utils/createDeferred.ts +48 -0
- package/src/unstable-core-do-not-import/stream/utils/createReadableStream.ts +31 -0
- package/src/unstable-core-do-not-import/stream/utils/createServer.ts +44 -0
- package/src/unstable-core-do-not-import/utils.ts +5 -0
- package/src/unstable-core-do-not-import.ts +5 -2
- package/dist/adapters/next-app-dir/formDataToObject.d.ts.map +0 -1
- package/dist/adapters/next-app-dir/formDataToObject.js +0 -34
- package/dist/adapters/next-app-dir/formDataToObject.mjs +0 -32
- package/dist/unstable-core-do-not-import/stream/stream.d.ts.map +0 -1
- /package/dist/{adapters/next-app-dir → unstable-core-do-not-import/http}/formDataToObject.d.ts +0 -0
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import {
|
|
3
|
+
isObservable,
|
|
4
|
+
observableToAsyncIterable,
|
|
5
|
+
} from '../../observable/observable';
|
|
2
6
|
import { getErrorShape } from '../error/getErrorShape';
|
|
3
7
|
import { getTRPCErrorFromUnknown, TRPCError } from '../error/TRPCError';
|
|
4
8
|
import type { ProcedureType } from '../procedure';
|
|
5
9
|
import {
|
|
6
|
-
callProcedure,
|
|
7
10
|
type AnyRouter,
|
|
8
11
|
type inferRouterContext,
|
|
9
12
|
type inferRouterError,
|
|
10
13
|
} from '../router';
|
|
11
14
|
import type { TRPCResponse } from '../rpc';
|
|
12
|
-
import { isPromise, jsonlStreamProducer } from '../stream/
|
|
15
|
+
import { isPromise, jsonlStreamProducer } from '../stream/jsonl';
|
|
16
|
+
import { sseHeaders, sseStreamProducer } from '../stream/sse';
|
|
13
17
|
import { transformTRPCResponse } from '../transformer';
|
|
14
|
-
import { isObject } from '../utils';
|
|
18
|
+
import { isAsyncIterable, isObject } from '../utils';
|
|
15
19
|
import { getRequestInfo } from './contentType';
|
|
16
20
|
import { getHTTPStatusCode } from './getHTTPStatusCode';
|
|
17
21
|
import type {
|
|
@@ -20,12 +24,28 @@ import type {
|
|
|
20
24
|
TRPCRequestInfo,
|
|
21
25
|
} from './types';
|
|
22
26
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
type HTTPMethods =
|
|
28
|
+
| 'GET'
|
|
29
|
+
| 'POST'
|
|
30
|
+
| 'HEAD'
|
|
31
|
+
| 'OPTIONS'
|
|
32
|
+
| 'PUT'
|
|
33
|
+
| 'DELETE'
|
|
34
|
+
| 'PATCH';
|
|
35
|
+
|
|
36
|
+
const TYPE_ACCEPTED_METHOD_MAP: Record<ProcedureType, HTTPMethods[]> = {
|
|
37
|
+
mutation: ['POST'],
|
|
38
|
+
query: ['GET'],
|
|
39
|
+
subscription: ['GET'],
|
|
40
|
+
};
|
|
41
|
+
const TYPE_ACCEPTED_METHOD_MAP_WITH_METHOD_OVERRIDE: Record<
|
|
42
|
+
ProcedureType,
|
|
43
|
+
HTTPMethods[]
|
|
26
44
|
> = {
|
|
27
|
-
GET
|
|
28
|
-
|
|
45
|
+
// never allow GET to do a mutation
|
|
46
|
+
mutation: ['POST'],
|
|
47
|
+
query: ['GET', 'POST'],
|
|
48
|
+
subscription: ['GET', 'POST'],
|
|
29
49
|
};
|
|
30
50
|
|
|
31
51
|
interface ResolveHTTPRequestOptions<TRouter extends AnyRouter>
|
|
@@ -42,19 +62,17 @@ interface ResolveHTTPRequestOptions<TRouter extends AnyRouter>
|
|
|
42
62
|
function initResponse<TRouter extends AnyRouter, TRequest>(initOpts: {
|
|
43
63
|
ctx: inferRouterContext<TRouter> | undefined;
|
|
44
64
|
info: TRPCRequestInfo | undefined;
|
|
45
|
-
type: ProcedureType | 'unknown';
|
|
46
65
|
responseMeta?: HTTPBaseHandlerOptions<TRouter, TRequest>['responseMeta'];
|
|
47
|
-
untransformedJSON
|
|
66
|
+
untransformedJSON:
|
|
48
67
|
| TRPCResponse<unknown, inferRouterError<TRouter>>
|
|
49
68
|
| TRPCResponse<unknown, inferRouterError<TRouter>>[]
|
|
50
|
-
|
|
|
69
|
+
| null;
|
|
51
70
|
errors: TRPCError[];
|
|
52
71
|
headers: Headers;
|
|
53
72
|
}) {
|
|
54
73
|
const {
|
|
55
74
|
ctx,
|
|
56
75
|
info,
|
|
57
|
-
type,
|
|
58
76
|
responseMeta,
|
|
59
77
|
untransformedJSON,
|
|
60
78
|
errors = [],
|
|
@@ -75,10 +93,12 @@ function initResponse<TRouter extends AnyRouter, TRequest>(initOpts: {
|
|
|
75
93
|
ctx,
|
|
76
94
|
info,
|
|
77
95
|
paths: info?.calls.map((call) => call.path),
|
|
78
|
-
type,
|
|
79
96
|
data,
|
|
80
97
|
errors,
|
|
81
98
|
eagerGeneration,
|
|
99
|
+
type:
|
|
100
|
+
info?.calls.find((call) => call.procedure?._def.type)?.procedure?._def
|
|
101
|
+
.type ?? 'unknown',
|
|
82
102
|
}) ?? {};
|
|
83
103
|
|
|
84
104
|
if (meta.headers) {
|
|
@@ -155,6 +175,25 @@ function caughtErrorToData<TRouter extends AnyRouter>(
|
|
|
155
175
|
};
|
|
156
176
|
}
|
|
157
177
|
|
|
178
|
+
/**
|
|
179
|
+
* Check if a value is a stream-like object
|
|
180
|
+
* - if it's an async iterable
|
|
181
|
+
* - if it's an object with async iterables or promises
|
|
182
|
+
*/
|
|
183
|
+
function isDataStream(v: unknown) {
|
|
184
|
+
if (!isObject(v)) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (isAsyncIterable(v)) {
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
Object.values(v).some(isPromise) || Object.values(v).some(isAsyncIterable)
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
|
|
158
197
|
export async function resolveResponse<TRouter extends AnyRouter>(
|
|
159
198
|
opts: ResolveHTTPRequestOptions<TRouter>,
|
|
160
199
|
): Promise<Response> {
|
|
@@ -170,26 +209,33 @@ export async function resolveResponse<TRouter extends AnyRouter>(
|
|
|
170
209
|
status: 204,
|
|
171
210
|
});
|
|
172
211
|
}
|
|
212
|
+
|
|
173
213
|
const allowBatching = opts.allowBatching ?? opts.batching?.enabled ?? true;
|
|
174
214
|
const allowMethodOverride =
|
|
175
215
|
(opts.allowMethodOverride ?? false) && req.method === 'POST';
|
|
176
|
-
|
|
177
|
-
const type =
|
|
178
|
-
HTTP_METHOD_PROCEDURE_TYPE_MAP[req.method] ?? ('unknown' as const);
|
|
179
216
|
let ctx: inferRouterContext<TRouter> | undefined = undefined;
|
|
180
217
|
let info: TRPCRequestInfo | undefined = undefined;
|
|
181
218
|
|
|
219
|
+
const methodMapper = allowMethodOverride
|
|
220
|
+
? TYPE_ACCEPTED_METHOD_MAP_WITH_METHOD_OVERRIDE
|
|
221
|
+
: TYPE_ACCEPTED_METHOD_MAP;
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* @deprecated
|
|
225
|
+
*/
|
|
182
226
|
const isStreamCall = req.headers.get('trpc-accept') === 'application/jsonl';
|
|
183
227
|
|
|
184
228
|
const experimentalIterablesAndDeferreds =
|
|
185
|
-
|
|
186
|
-
|
|
229
|
+
router._def._config.experimental?.iterablesAndDeferreds ?? true;
|
|
230
|
+
const experimentalSSE =
|
|
231
|
+
router._def._config.experimental?.sseSubscriptions?.enabled ?? true;
|
|
187
232
|
try {
|
|
188
233
|
info = getRequestInfo({
|
|
189
234
|
req,
|
|
190
235
|
path: decodeURIComponent(opts.path),
|
|
191
|
-
|
|
236
|
+
router,
|
|
192
237
|
searchParams: url.searchParams,
|
|
238
|
+
headers: opts.req.headers,
|
|
193
239
|
});
|
|
194
240
|
|
|
195
241
|
// we create context early so that error handlers may access context information
|
|
@@ -206,56 +252,49 @@ export async function resolveResponse<TRouter extends AnyRouter>(
|
|
|
206
252
|
message: `Batching is not enabled on the server`,
|
|
207
253
|
});
|
|
208
254
|
}
|
|
209
|
-
if
|
|
255
|
+
/* istanbul ignore if -- @preserve */
|
|
256
|
+
if (isStreamCall && !info.isBatchCall) {
|
|
210
257
|
throw new TRPCError({
|
|
211
|
-
message: `
|
|
212
|
-
code: '
|
|
258
|
+
message: `Streaming requests must be batched (you can do a batch of 1)`,
|
|
259
|
+
code: 'BAD_REQUEST',
|
|
213
260
|
});
|
|
214
261
|
}
|
|
215
262
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
263
|
+
type RPCResult =
|
|
264
|
+
| [result: null, error: TRPCError]
|
|
265
|
+
| [result: unknown, error?: never];
|
|
266
|
+
const rpcCalls = info.calls.map(async (call): Promise<RPCResult> => {
|
|
267
|
+
const proc = call.procedure;
|
|
221
268
|
try {
|
|
222
|
-
|
|
223
|
-
|
|
269
|
+
if (!proc) {
|
|
270
|
+
throw new TRPCError({
|
|
271
|
+
code: 'NOT_FOUND',
|
|
272
|
+
message: `No procedure found on path "${call.path}"`,
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (!methodMapper[proc._def.type].includes(req.method as HTTPMethods)) {
|
|
277
|
+
throw new TRPCError({
|
|
278
|
+
code: 'METHOD_NOT_SUPPORTED',
|
|
279
|
+
message: `Unsupported ${req.method}-request to ${proc._def.type} procedure at path "${call.path}"`,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
/* istanbul ignore if -- @preserve */
|
|
283
|
+
if (proc._def.type === 'subscription' && info!.isBatchCall) {
|
|
284
|
+
throw new TRPCError({
|
|
285
|
+
code: 'BAD_REQUEST',
|
|
286
|
+
message: `Cannot batch subscription calls`,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
const data: unknown = await proc({
|
|
224
290
|
path: call.path,
|
|
225
291
|
getRawInput: call.getRawInput,
|
|
226
292
|
ctx,
|
|
227
|
-
type,
|
|
228
|
-
allowMethodOverride,
|
|
293
|
+
type: proc._def.type,
|
|
229
294
|
});
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
(!isStreamCall || !experimentalIterablesAndDeferreds) &&
|
|
233
|
-
isObject(data) &&
|
|
234
|
-
(Symbol.asyncIterator in data || Object.values(data).some(isPromise))
|
|
235
|
-
) {
|
|
236
|
-
if (!isStreamCall) {
|
|
237
|
-
throw new TRPCError({
|
|
238
|
-
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
239
|
-
message:
|
|
240
|
-
'Cannot return async iterable or nested promises in non-streaming response',
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
if (!experimentalIterablesAndDeferreds) {
|
|
244
|
-
throw new TRPCError({
|
|
245
|
-
code: 'INTERNAL_SERVER_ERROR',
|
|
246
|
-
message: 'Missing experimental flag "iterablesAndDeferreds"',
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
return {
|
|
252
|
-
result: {
|
|
253
|
-
data,
|
|
254
|
-
},
|
|
255
|
-
};
|
|
295
|
+
return [data];
|
|
256
296
|
} catch (cause) {
|
|
257
297
|
const error = getTRPCErrorFromUnknown(cause);
|
|
258
|
-
errors.push(error);
|
|
259
298
|
const input = call.result();
|
|
260
299
|
|
|
261
300
|
opts.onError?.({
|
|
@@ -263,141 +302,272 @@ export async function resolveResponse<TRouter extends AnyRouter>(
|
|
|
263
302
|
path: call.path,
|
|
264
303
|
input,
|
|
265
304
|
ctx,
|
|
266
|
-
type: type,
|
|
305
|
+
type: call.procedure?._def.type ?? 'unknown',
|
|
267
306
|
req: opts.req,
|
|
268
307
|
});
|
|
269
308
|
|
|
270
|
-
return
|
|
271
|
-
error: getErrorShape({
|
|
272
|
-
config,
|
|
273
|
-
error,
|
|
274
|
-
type,
|
|
275
|
-
path: call.path,
|
|
276
|
-
input,
|
|
277
|
-
ctx,
|
|
278
|
-
}),
|
|
279
|
-
};
|
|
309
|
+
return [null, error];
|
|
280
310
|
}
|
|
281
311
|
});
|
|
282
|
-
if (!isStreamCall) {
|
|
283
|
-
headers.set('content-type', 'application/json');
|
|
284
|
-
/**
|
|
285
|
-
* Non-streaming response:
|
|
286
|
-
* - await all responses in parallel, blocking on the slowest one
|
|
287
|
-
* - create headers with known response body
|
|
288
|
-
* - return a complete HTTPResponse
|
|
289
|
-
*/
|
|
290
312
|
|
|
291
|
-
|
|
313
|
+
// ----------- response handlers -----------
|
|
314
|
+
if (!info.isBatchCall) {
|
|
315
|
+
const [call] = info.calls;
|
|
316
|
+
const [data, error] = await rpcCalls[0]!;
|
|
292
317
|
|
|
293
|
-
|
|
294
|
-
'
|
|
295
|
-
|
|
318
|
+
switch (info.type) {
|
|
319
|
+
case 'unknown':
|
|
320
|
+
case 'mutation':
|
|
321
|
+
case 'query': {
|
|
322
|
+
// httpLink
|
|
323
|
+
headers.set('content-type', 'application/json');
|
|
296
324
|
|
|
325
|
+
if (isDataStream(data)) {
|
|
326
|
+
throw new TRPCError({
|
|
327
|
+
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
328
|
+
message:
|
|
329
|
+
'Cannot use stream-like response in non-streaming request - use httpBatchStreamLink',
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
const res: TRPCResponse<unknown, inferRouterError<TRouter>> = error
|
|
333
|
+
? {
|
|
334
|
+
error: getErrorShape({
|
|
335
|
+
config,
|
|
336
|
+
ctx,
|
|
337
|
+
error,
|
|
338
|
+
input: call!.result(),
|
|
339
|
+
path: call!.path,
|
|
340
|
+
type: info.type,
|
|
341
|
+
}),
|
|
342
|
+
}
|
|
343
|
+
: { result: { data } };
|
|
344
|
+
|
|
345
|
+
const headResponse = initResponse({
|
|
346
|
+
ctx,
|
|
347
|
+
info,
|
|
348
|
+
responseMeta: opts.responseMeta,
|
|
349
|
+
errors: error ? [error] : [],
|
|
350
|
+
headers,
|
|
351
|
+
untransformedJSON: [res],
|
|
352
|
+
});
|
|
353
|
+
return new Response(
|
|
354
|
+
JSON.stringify(transformTRPCResponse(config, res)),
|
|
355
|
+
{
|
|
356
|
+
status: headResponse.status,
|
|
357
|
+
headers,
|
|
358
|
+
},
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
case 'subscription': {
|
|
362
|
+
// httpSubscriptionLink
|
|
363
|
+
|
|
364
|
+
if (!experimentalSSE) {
|
|
365
|
+
throw new TRPCError({
|
|
366
|
+
code: 'METHOD_NOT_SUPPORTED',
|
|
367
|
+
message: 'Missing experimental flag "sseSubscriptions"',
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (!isObservable(data) && !isAsyncIterable(data)) {
|
|
372
|
+
throw new TRPCError({
|
|
373
|
+
message: `Subscription ${
|
|
374
|
+
call!.path
|
|
375
|
+
} did not return an observable or a AsyncGenerator`,
|
|
376
|
+
code: 'INTERNAL_SERVER_ERROR',
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
const dataAsIterable = isObservable(data)
|
|
380
|
+
? observableToAsyncIterable(data)
|
|
381
|
+
: data;
|
|
382
|
+
const stream = sseStreamProducer({
|
|
383
|
+
data: dataAsIterable,
|
|
384
|
+
serialize: (v) => config.transformer.output.serialize(v),
|
|
385
|
+
});
|
|
386
|
+
for (const [key, value] of Object.entries(sseHeaders)) {
|
|
387
|
+
headers.set(key, value);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const headResponse = initResponse({
|
|
391
|
+
ctx,
|
|
392
|
+
info,
|
|
393
|
+
responseMeta: opts.responseMeta,
|
|
394
|
+
errors: [],
|
|
395
|
+
headers,
|
|
396
|
+
untransformedJSON: null,
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
return new Response(stream, {
|
|
400
|
+
headers,
|
|
401
|
+
status: headResponse.status,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// batch response handlers
|
|
408
|
+
if (info.accept === 'application/jsonl') {
|
|
409
|
+
// httpBatchStreamLink
|
|
410
|
+
headers.set('content-type', 'application/json');
|
|
411
|
+
headers.set('transfer-encoding', 'chunked');
|
|
297
412
|
const headResponse = initResponse({
|
|
298
413
|
ctx,
|
|
299
414
|
info,
|
|
300
|
-
type,
|
|
301
415
|
responseMeta: opts.responseMeta,
|
|
302
|
-
|
|
303
|
-
errors,
|
|
416
|
+
errors: [],
|
|
304
417
|
headers,
|
|
418
|
+
untransformedJSON: null,
|
|
305
419
|
});
|
|
420
|
+
const stream = jsonlStreamProducer({
|
|
421
|
+
/**
|
|
422
|
+
* Example structure for `maxDepth: 4`:
|
|
423
|
+
* {
|
|
424
|
+
* // 1
|
|
425
|
+
* 0: {
|
|
426
|
+
* // 2
|
|
427
|
+
* result: {
|
|
428
|
+
* // 3
|
|
429
|
+
* data: // 4
|
|
430
|
+
* }
|
|
431
|
+
* }
|
|
432
|
+
* }
|
|
433
|
+
*/
|
|
434
|
+
maxDepth: experimentalIterablesAndDeferreds ? 4 : 3,
|
|
435
|
+
data: rpcCalls.map(async (res) => {
|
|
436
|
+
const [result, error] = await res;
|
|
437
|
+
|
|
438
|
+
const call = info!.calls[0];
|
|
439
|
+
if (error) {
|
|
440
|
+
return {
|
|
441
|
+
error: getErrorShape({
|
|
442
|
+
config,
|
|
443
|
+
ctx,
|
|
444
|
+
error,
|
|
445
|
+
input: call!.result(),
|
|
446
|
+
path: call!.path,
|
|
447
|
+
type: call!.procedure?._def.type ?? 'unknown',
|
|
448
|
+
}),
|
|
449
|
+
};
|
|
450
|
+
}
|
|
306
451
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
452
|
+
/**
|
|
453
|
+
* Not very pretty, but we need to wrap nested data in promises
|
|
454
|
+
* Our stream producer will only resolve top-level async values or async values that are directly nested in another async value
|
|
455
|
+
*/
|
|
456
|
+
const data = isObservable(result)
|
|
457
|
+
? observableToAsyncIterable(result)
|
|
458
|
+
: Promise.resolve(result);
|
|
459
|
+
return {
|
|
460
|
+
result: Promise.resolve({
|
|
461
|
+
data,
|
|
462
|
+
}),
|
|
463
|
+
};
|
|
464
|
+
}),
|
|
465
|
+
serialize: config.transformer.output.serialize,
|
|
466
|
+
onError: (cause) => {
|
|
467
|
+
opts.onError?.({
|
|
468
|
+
error: getTRPCErrorFromUnknown(cause),
|
|
469
|
+
path: undefined,
|
|
470
|
+
input: undefined,
|
|
471
|
+
ctx,
|
|
472
|
+
req: opts.req,
|
|
473
|
+
type: info?.type ?? 'unknown',
|
|
474
|
+
});
|
|
475
|
+
},
|
|
476
|
+
|
|
477
|
+
formatError(errorOpts) {
|
|
478
|
+
const call = info?.calls[errorOpts.path[0] as any];
|
|
479
|
+
|
|
480
|
+
const shape = getErrorShape({
|
|
481
|
+
config,
|
|
482
|
+
ctx,
|
|
483
|
+
error: getTRPCErrorFromUnknown(errorOpts.error),
|
|
484
|
+
input: call?.result(),
|
|
485
|
+
path: call?.path,
|
|
486
|
+
type: call?.procedure?._def.type ?? 'unknown',
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
return shape;
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
|
|
493
|
+
return new Response(stream, {
|
|
319
494
|
headers,
|
|
495
|
+
status: headResponse.status,
|
|
320
496
|
});
|
|
321
497
|
}
|
|
322
498
|
|
|
323
|
-
|
|
324
|
-
headers.set('transfer-encoding', 'chunked');
|
|
499
|
+
// httpBatchLink
|
|
325
500
|
/**
|
|
326
|
-
*
|
|
327
|
-
* -
|
|
328
|
-
* - create headers with
|
|
329
|
-
* - return
|
|
501
|
+
* Non-streaming response:
|
|
502
|
+
* - await all responses in parallel, blocking on the slowest one
|
|
503
|
+
* - create headers with known response body
|
|
504
|
+
* - return a complete HTTPResponse
|
|
330
505
|
*/
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
});
|
|
339
|
-
|
|
340
|
-
const stream = jsonlStreamProducer({
|
|
341
|
-
/**
|
|
342
|
-
* Example structure for `maxDepth: 4`:
|
|
343
|
-
* {
|
|
344
|
-
* // 1
|
|
345
|
-
* 0: {
|
|
346
|
-
* // 2
|
|
347
|
-
* result: {
|
|
348
|
-
* // 3
|
|
349
|
-
* data: // 4
|
|
350
|
-
* }
|
|
351
|
-
* }
|
|
352
|
-
* }
|
|
353
|
-
*/
|
|
354
|
-
maxDepth: experimentalIterablesAndDeferreds ? 4 : 3,
|
|
355
|
-
formatError(errorOpts) {
|
|
356
|
-
const call = info?.calls[errorOpts.path[0] as any];
|
|
506
|
+
headers.set('content-type', 'application/json');
|
|
507
|
+
const results: RPCResult[] = (await Promise.all(rpcCalls)).map(
|
|
508
|
+
(res): RPCResult => {
|
|
509
|
+
const [data, error] = res;
|
|
510
|
+
if (error) {
|
|
511
|
+
return res;
|
|
512
|
+
}
|
|
357
513
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
514
|
+
if (isDataStream(data)) {
|
|
515
|
+
return [
|
|
516
|
+
null,
|
|
517
|
+
new TRPCError({
|
|
518
|
+
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
519
|
+
message:
|
|
520
|
+
'Cannot use stream-like response in non-streaming request - use httpBatchStreamLink',
|
|
521
|
+
}),
|
|
522
|
+
];
|
|
523
|
+
}
|
|
524
|
+
return res;
|
|
366
525
|
},
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
526
|
+
);
|
|
527
|
+
const resultAsRPCResponse = results.map(
|
|
528
|
+
(
|
|
529
|
+
[data, error],
|
|
530
|
+
index,
|
|
531
|
+
): TRPCResponse<unknown, inferRouterError<TRouter>> => {
|
|
532
|
+
const call = info!.calls[index]!;
|
|
533
|
+
if (error) {
|
|
374
534
|
return {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
535
|
+
error: getErrorShape({
|
|
536
|
+
config,
|
|
537
|
+
ctx,
|
|
538
|
+
error,
|
|
539
|
+
input: call.result(),
|
|
540
|
+
path: call.path,
|
|
541
|
+
type: call.procedure?._def.type ?? 'unknown',
|
|
379
542
|
}),
|
|
380
543
|
};
|
|
381
544
|
}
|
|
382
|
-
return
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
onError: (cause) => {
|
|
386
|
-
opts.onError?.({
|
|
387
|
-
error: getTRPCErrorFromUnknown(cause),
|
|
388
|
-
path: undefined,
|
|
389
|
-
input: undefined,
|
|
390
|
-
ctx,
|
|
391
|
-
type,
|
|
392
|
-
req: opts.req,
|
|
393
|
-
});
|
|
545
|
+
return {
|
|
546
|
+
result: { data },
|
|
547
|
+
};
|
|
394
548
|
},
|
|
395
|
-
|
|
549
|
+
);
|
|
396
550
|
|
|
397
|
-
|
|
551
|
+
const errors = results
|
|
552
|
+
.map(([_, error]) => error)
|
|
553
|
+
.filter(Boolean) as TRPCError[];
|
|
554
|
+
|
|
555
|
+
const headResponse = initResponse({
|
|
556
|
+
ctx,
|
|
557
|
+
info,
|
|
558
|
+
responseMeta: opts.responseMeta,
|
|
559
|
+
untransformedJSON: resultAsRPCResponse,
|
|
560
|
+
errors,
|
|
398
561
|
headers,
|
|
399
|
-
status: headResponse.status,
|
|
400
562
|
});
|
|
563
|
+
|
|
564
|
+
return new Response(
|
|
565
|
+
JSON.stringify(transformTRPCResponse(config, resultAsRPCResponse)),
|
|
566
|
+
{
|
|
567
|
+
status: headResponse.status,
|
|
568
|
+
headers,
|
|
569
|
+
},
|
|
570
|
+
);
|
|
401
571
|
} catch (cause) {
|
|
402
572
|
// we get here if
|
|
403
573
|
// - batching is called when it's not enabled
|
|
@@ -409,13 +579,12 @@ export async function resolveResponse<TRouter extends AnyRouter>(
|
|
|
409
579
|
const { error, untransformedJSON, body } = caughtErrorToData(cause, {
|
|
410
580
|
opts,
|
|
411
581
|
ctx,
|
|
412
|
-
type,
|
|
582
|
+
type: info?.type ?? 'unknown',
|
|
413
583
|
});
|
|
414
584
|
|
|
415
585
|
const headResponse = initResponse({
|
|
416
586
|
ctx,
|
|
417
587
|
info,
|
|
418
|
-
type,
|
|
419
588
|
responseMeta: opts.responseMeta,
|
|
420
589
|
untransformedJSON,
|
|
421
590
|
errors: [error],
|