@trpc/server 11.0.0-rc.417 → 11.0.0-rc.421
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/index.d.ts +1 -1
- package/dist/@trpc/server/index.d.ts.map +1 -1
- package/dist/adapters/aws-lambda/getPlanner.d.ts.map +1 -1
- package/dist/adapters/next-app-dir/redirect.d.ts.map +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 +1 -2
- package/dist/adapters/ws.d.ts.map +1 -1
- package/dist/adapters/ws.js +98 -81
- package/dist/adapters/ws.mjs +98 -81
- package/dist/bundle-analysis.json +183 -124
- package/dist/index.js +5 -3
- package/dist/index.mjs +2 -1
- 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.map +1 -1
- 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 +55 -17
- package/dist/unstable-core-do-not-import/http/contentType.mjs +56 -18
- 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 +34 -5
- 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 +6 -0
- package/dist/unstable-core-do-not-import/router.mjs +6 -0
- 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} +90 -89
- package/dist/unstable-core-do-not-import/stream/{stream.mjs → jsonl.mjs} +89 -88
- 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 +2 -1
- package/dist/unstable-core-do-not-import.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import.js +11 -4
- package/dist/unstable-core-do-not-import.mjs +3 -2
- package/package.json +3 -3
- package/src/@trpc/server/index.ts +1 -0
- package/src/adapters/node-http/incomingMessageToRequest.ts +3 -2
- package/src/adapters/node-http/nodeHTTPRequestHandler.ts +32 -7
- package/src/adapters/ws.ts +101 -75
- package/src/observable/observable.ts +63 -0
- package/src/unstable-core-do-not-import/http/contentType.ts +78 -21
- package/src/unstable-core-do-not-import/http/resolveResponse.ts +331 -164
- package/src/unstable-core-do-not-import/http/types.ts +42 -5
- 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 +12 -0
- package/src/unstable-core-do-not-import/stream/{stream.ts → jsonl.ts} +99 -85
- 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 +46 -0
- package/src/unstable-core-do-not-import/utils.ts +5 -0
- package/src/unstable-core-do-not-import.ts +2 -1
- package/dist/unstable-core-do-not-import/stream/stream.d.ts.map +0 -1
|
@@ -1,18 +1,40 @@
|
|
|
1
|
+
import { isObservable, observableToAsyncIterable } from '../../observable/observable.mjs';
|
|
1
2
|
import { getErrorShape } from '../error/getErrorShape.mjs';
|
|
2
3
|
import { TRPCError, getTRPCErrorFromUnknown } from '../error/TRPCError.mjs';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
4
|
+
import { jsonlStreamProducer, isPromise } from '../stream/jsonl.mjs';
|
|
5
|
+
import { sseStreamProducer, sseHeaders } from '../stream/sse.mjs';
|
|
5
6
|
import { transformTRPCResponse } from '../transformer.mjs';
|
|
6
|
-
import { isObject } from '../utils.mjs';
|
|
7
|
+
import { isAsyncIterable, isObject } from '../utils.mjs';
|
|
7
8
|
import { getRequestInfo } from './contentType.mjs';
|
|
8
9
|
import { getHTTPStatusCode } from './getHTTPStatusCode.mjs';
|
|
9
10
|
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
const TYPE_ACCEPTED_METHOD_MAP = {
|
|
12
|
+
mutation: [
|
|
13
|
+
'POST'
|
|
14
|
+
],
|
|
15
|
+
query: [
|
|
16
|
+
'GET'
|
|
17
|
+
],
|
|
18
|
+
subscription: [
|
|
19
|
+
'GET'
|
|
20
|
+
]
|
|
21
|
+
};
|
|
22
|
+
const TYPE_ACCEPTED_METHOD_MAP_WITH_METHOD_OVERRIDE = {
|
|
23
|
+
// never allow GET to do a mutation
|
|
24
|
+
mutation: [
|
|
25
|
+
'POST'
|
|
26
|
+
],
|
|
27
|
+
query: [
|
|
28
|
+
'GET',
|
|
29
|
+
'POST'
|
|
30
|
+
],
|
|
31
|
+
subscription: [
|
|
32
|
+
'GET',
|
|
33
|
+
'POST'
|
|
34
|
+
]
|
|
13
35
|
};
|
|
14
36
|
function initResponse(initOpts) {
|
|
15
|
-
const { ctx , info ,
|
|
37
|
+
const { ctx , info , responseMeta , untransformedJSON , errors =[] , headers , } = initOpts;
|
|
16
38
|
let status = untransformedJSON ? getHTTPStatusCode(untransformedJSON) : 200;
|
|
17
39
|
const eagerGeneration = !untransformedJSON;
|
|
18
40
|
const data = eagerGeneration ? [] : Array.isArray(untransformedJSON) ? untransformedJSON : [
|
|
@@ -22,10 +44,10 @@ function initResponse(initOpts) {
|
|
|
22
44
|
ctx,
|
|
23
45
|
info,
|
|
24
46
|
paths: info?.calls.map((call)=>call.path),
|
|
25
|
-
type,
|
|
26
47
|
data,
|
|
27
48
|
errors,
|
|
28
|
-
eagerGeneration
|
|
49
|
+
eagerGeneration,
|
|
50
|
+
type: info?.calls.find((call)=>call.procedure?._def.type)?.procedure?._def.type ?? 'unknown'
|
|
29
51
|
}) ?? {};
|
|
30
52
|
if (meta.headers) {
|
|
31
53
|
if (meta.headers instanceof Headers) {
|
|
@@ -82,6 +104,19 @@ function caughtErrorToData(cause, errorOpts) {
|
|
|
82
104
|
body
|
|
83
105
|
};
|
|
84
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if a value is a stream-like object
|
|
109
|
+
* - if it's an async iterable
|
|
110
|
+
* - if it's an object with async iterables or promises
|
|
111
|
+
*/ function isDataStream(v) {
|
|
112
|
+
if (!isObject(v)) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
if (isAsyncIterable(v)) {
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
return Object.values(v).some(isPromise) || Object.values(v).some(isAsyncIterable);
|
|
119
|
+
}
|
|
85
120
|
async function resolveResponse(opts) {
|
|
86
121
|
const { router , req } = opts;
|
|
87
122
|
const headers = new Headers([
|
|
@@ -100,17 +135,21 @@ async function resolveResponse(opts) {
|
|
|
100
135
|
}
|
|
101
136
|
const allowBatching = opts.allowBatching ?? opts.batching?.enabled ?? true;
|
|
102
137
|
const allowMethodOverride = (opts.allowMethodOverride ?? false) && req.method === 'POST';
|
|
103
|
-
const type = HTTP_METHOD_PROCEDURE_TYPE_MAP[req.method] ?? 'unknown';
|
|
104
138
|
let ctx = undefined;
|
|
105
139
|
let info = undefined;
|
|
106
|
-
const
|
|
107
|
-
|
|
140
|
+
const methodMapper = allowMethodOverride ? TYPE_ACCEPTED_METHOD_MAP_WITH_METHOD_OVERRIDE : TYPE_ACCEPTED_METHOD_MAP;
|
|
141
|
+
/**
|
|
142
|
+
* @deprecated
|
|
143
|
+
*/ const isStreamCall = req.headers.get('trpc-accept') === 'application/jsonl';
|
|
144
|
+
const experimentalIterablesAndDeferreds = router._def._config.experimental?.iterablesAndDeferreds ?? true;
|
|
145
|
+
const experimentalSSE = router._def._config.experimental?.sseSubscriptions?.enabled ?? true;
|
|
108
146
|
try {
|
|
109
147
|
info = getRequestInfo({
|
|
110
148
|
req,
|
|
111
149
|
path: decodeURIComponent(opts.path),
|
|
112
|
-
|
|
113
|
-
searchParams: url.searchParams
|
|
150
|
+
router,
|
|
151
|
+
searchParams: url.searchParams,
|
|
152
|
+
headers: opts.req.headers
|
|
114
153
|
});
|
|
115
154
|
// we create context early so that error handlers may access context information
|
|
116
155
|
ctx = await opts.createContext({
|
|
@@ -125,166 +164,281 @@ async function resolveResponse(opts) {
|
|
|
125
164
|
message: `Batching is not enabled on the server`
|
|
126
165
|
});
|
|
127
166
|
}
|
|
128
|
-
if (
|
|
167
|
+
/* istanbul ignore if -- @preserve */ if (isStreamCall && !info.isBatchCall) {
|
|
129
168
|
throw new TRPCError({
|
|
130
|
-
message: `
|
|
131
|
-
code: '
|
|
169
|
+
message: `Streaming requests must be batched (you can do a batch of 1)`,
|
|
170
|
+
code: 'BAD_REQUEST'
|
|
132
171
|
});
|
|
133
172
|
}
|
|
134
|
-
const
|
|
135
|
-
|
|
173
|
+
const rpcCalls = info.calls.map(async (call)=>{
|
|
174
|
+
const proc = call.procedure;
|
|
136
175
|
try {
|
|
137
|
-
|
|
138
|
-
|
|
176
|
+
if (!proc) {
|
|
177
|
+
throw new TRPCError({
|
|
178
|
+
code: 'NOT_FOUND',
|
|
179
|
+
message: `No procedure found on path "${call.path}"`
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (!methodMapper[proc._def.type].includes(req.method)) {
|
|
183
|
+
throw new TRPCError({
|
|
184
|
+
code: 'METHOD_NOT_SUPPORTED',
|
|
185
|
+
message: `Unsupported ${req.method}-request to ${proc._def.type} procedure at path "${call.path}"`
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/* istanbul ignore if -- @preserve */ if (proc._def.type === 'subscription' && info.isBatchCall) {
|
|
189
|
+
throw new TRPCError({
|
|
190
|
+
code: 'BAD_REQUEST',
|
|
191
|
+
message: `Cannot batch subscription calls`
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
const data = await proc({
|
|
139
195
|
path: call.path,
|
|
140
196
|
getRawInput: call.getRawInput,
|
|
141
197
|
ctx,
|
|
142
|
-
type
|
|
143
|
-
allowMethodOverride
|
|
198
|
+
type: proc._def.type
|
|
144
199
|
});
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
149
|
-
message: 'Cannot return async iterable or nested promises in non-streaming response'
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
if (!experimentalIterablesAndDeferreds) {
|
|
153
|
-
throw new TRPCError({
|
|
154
|
-
code: 'INTERNAL_SERVER_ERROR',
|
|
155
|
-
message: 'Missing experimental flag "iterablesAndDeferreds"'
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
return {
|
|
160
|
-
result: {
|
|
161
|
-
data
|
|
162
|
-
}
|
|
163
|
-
};
|
|
200
|
+
return [
|
|
201
|
+
data
|
|
202
|
+
];
|
|
164
203
|
} catch (cause) {
|
|
165
204
|
const error = getTRPCErrorFromUnknown(cause);
|
|
166
|
-
errors.push(error);
|
|
167
205
|
const input = call.result();
|
|
168
206
|
opts.onError?.({
|
|
169
207
|
error,
|
|
170
208
|
path: call.path,
|
|
171
209
|
input,
|
|
172
210
|
ctx,
|
|
173
|
-
type: type,
|
|
211
|
+
type: call.procedure?._def.type ?? 'unknown',
|
|
174
212
|
req: opts.req
|
|
175
213
|
});
|
|
176
|
-
return
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
type,
|
|
181
|
-
path: call.path,
|
|
182
|
-
input,
|
|
183
|
-
ctx
|
|
184
|
-
})
|
|
185
|
-
};
|
|
214
|
+
return [
|
|
215
|
+
null,
|
|
216
|
+
error
|
|
217
|
+
];
|
|
186
218
|
}
|
|
187
219
|
});
|
|
188
|
-
|
|
220
|
+
// ----------- response handlers -----------
|
|
221
|
+
if (!info.isBatchCall) {
|
|
222
|
+
const [call] = info.calls;
|
|
223
|
+
const [data, error] = await rpcCalls[0];
|
|
224
|
+
switch(info.type){
|
|
225
|
+
case 'unknown':
|
|
226
|
+
case 'mutation':
|
|
227
|
+
case 'query':
|
|
228
|
+
{
|
|
229
|
+
// httpLink
|
|
230
|
+
headers.set('content-type', 'application/json');
|
|
231
|
+
if (isDataStream(data)) {
|
|
232
|
+
throw new TRPCError({
|
|
233
|
+
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
234
|
+
message: 'Cannot use stream-like response in non-streaming request - use httpBatchStreamLink'
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
const res = error ? {
|
|
238
|
+
error: getErrorShape({
|
|
239
|
+
config,
|
|
240
|
+
ctx,
|
|
241
|
+
error,
|
|
242
|
+
input: call.result(),
|
|
243
|
+
path: call.path,
|
|
244
|
+
type: info.type
|
|
245
|
+
})
|
|
246
|
+
} : {
|
|
247
|
+
result: {
|
|
248
|
+
data
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
const headResponse = initResponse({
|
|
252
|
+
ctx,
|
|
253
|
+
info,
|
|
254
|
+
responseMeta: opts.responseMeta,
|
|
255
|
+
errors: error ? [
|
|
256
|
+
error
|
|
257
|
+
] : [],
|
|
258
|
+
headers,
|
|
259
|
+
untransformedJSON: [
|
|
260
|
+
res
|
|
261
|
+
]
|
|
262
|
+
});
|
|
263
|
+
return new Response(JSON.stringify(transformTRPCResponse(config, res)), {
|
|
264
|
+
status: headResponse.status,
|
|
265
|
+
headers
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
case 'subscription':
|
|
269
|
+
{
|
|
270
|
+
// httpSubscriptionLink
|
|
271
|
+
if (!experimentalSSE) {
|
|
272
|
+
throw new TRPCError({
|
|
273
|
+
code: 'METHOD_NOT_SUPPORTED',
|
|
274
|
+
message: 'Missing experimental flag "sseSubscriptions"'
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
if (!isObservable(data) && !isAsyncIterable(data)) {
|
|
278
|
+
throw new TRPCError({
|
|
279
|
+
message: `Subscription ${call.path} did not return an observable or a AsyncGenerator`,
|
|
280
|
+
code: 'INTERNAL_SERVER_ERROR'
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
const dataAsIterable = isObservable(data) ? observableToAsyncIterable(data) : data;
|
|
284
|
+
const stream = sseStreamProducer({
|
|
285
|
+
data: dataAsIterable,
|
|
286
|
+
serialize: (v)=>config.transformer.output.serialize(v)
|
|
287
|
+
});
|
|
288
|
+
for (const [key, value] of Object.entries(sseHeaders)){
|
|
289
|
+
headers.set(key, value);
|
|
290
|
+
}
|
|
291
|
+
const headResponse1 = initResponse({
|
|
292
|
+
ctx,
|
|
293
|
+
info,
|
|
294
|
+
responseMeta: opts.responseMeta,
|
|
295
|
+
errors: [],
|
|
296
|
+
headers,
|
|
297
|
+
untransformedJSON: null
|
|
298
|
+
});
|
|
299
|
+
return new Response(stream, {
|
|
300
|
+
headers,
|
|
301
|
+
status: headResponse1.status
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
// batch response handlers
|
|
307
|
+
if (info.accept === 'application/jsonl') {
|
|
308
|
+
// httpBatchStreamLink
|
|
189
309
|
headers.set('content-type', 'application/json');
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
* - await all responses in parallel, blocking on the slowest one
|
|
193
|
-
* - create headers with known response body
|
|
194
|
-
* - return a complete HTTPResponse
|
|
195
|
-
*/ const untransformedJSON = await Promise.all(promises);
|
|
196
|
-
const errors1 = untransformedJSON.flatMap((response)=>'error' in response ? [
|
|
197
|
-
response.error
|
|
198
|
-
] : []);
|
|
199
|
-
const headResponse = initResponse({
|
|
310
|
+
headers.set('transfer-encoding', 'chunked');
|
|
311
|
+
const headResponse2 = initResponse({
|
|
200
312
|
ctx,
|
|
201
313
|
info,
|
|
202
|
-
type,
|
|
203
314
|
responseMeta: opts.responseMeta,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
315
|
+
errors: [],
|
|
316
|
+
headers,
|
|
317
|
+
untransformedJSON: null
|
|
207
318
|
});
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
* 0: {
|
|
238
|
-
* // 2
|
|
239
|
-
* result: {
|
|
240
|
-
* // 3
|
|
241
|
-
* data: // 4
|
|
242
|
-
* }
|
|
243
|
-
* }
|
|
244
|
-
* }
|
|
245
|
-
*/ maxDepth: experimentalIterablesAndDeferreds ? 4 : 3,
|
|
246
|
-
formatError (errorOpts) {
|
|
247
|
-
const call = info?.calls[errorOpts.path[0]];
|
|
248
|
-
return getErrorShape({
|
|
249
|
-
config,
|
|
250
|
-
ctx,
|
|
251
|
-
error: getTRPCErrorFromUnknown(errorOpts.error),
|
|
252
|
-
input: call?.result(),
|
|
253
|
-
path: call?.path,
|
|
254
|
-
type
|
|
255
|
-
});
|
|
256
|
-
},
|
|
257
|
-
data: promises.map(async (it)=>{
|
|
258
|
-
const response = await it;
|
|
259
|
-
if ('result' in response) {
|
|
319
|
+
const stream1 = jsonlStreamProducer({
|
|
320
|
+
/**
|
|
321
|
+
* Example structure for `maxDepth: 4`:
|
|
322
|
+
* {
|
|
323
|
+
* // 1
|
|
324
|
+
* 0: {
|
|
325
|
+
* // 2
|
|
326
|
+
* result: {
|
|
327
|
+
* // 3
|
|
328
|
+
* data: // 4
|
|
329
|
+
* }
|
|
330
|
+
* }
|
|
331
|
+
* }
|
|
332
|
+
*/ maxDepth: experimentalIterablesAndDeferreds ? 4 : 3,
|
|
333
|
+
data: rpcCalls.map(async (res)=>{
|
|
334
|
+
const [result, error] = await res;
|
|
335
|
+
const call = info.calls[0];
|
|
336
|
+
if (error) {
|
|
337
|
+
return {
|
|
338
|
+
error: getErrorShape({
|
|
339
|
+
config,
|
|
340
|
+
ctx,
|
|
341
|
+
error,
|
|
342
|
+
input: call.result(),
|
|
343
|
+
path: call.path,
|
|
344
|
+
type: call.procedure?._def.type ?? 'unknown'
|
|
345
|
+
})
|
|
346
|
+
};
|
|
347
|
+
}
|
|
260
348
|
/**
|
|
261
349
|
* Not very pretty, but we need to wrap nested data in promises
|
|
262
350
|
* Our stream producer will only resolve top-level async values or async values that are directly nested in another async value
|
|
263
|
-
*/
|
|
264
|
-
|
|
351
|
+
*/ const data = isObservable(result) ? observableToAsyncIterable(result) : Promise.resolve(result);
|
|
352
|
+
return {
|
|
265
353
|
result: Promise.resolve({
|
|
266
|
-
|
|
267
|
-
data: Promise.resolve(response.result.data)
|
|
354
|
+
data
|
|
268
355
|
})
|
|
269
356
|
};
|
|
357
|
+
}),
|
|
358
|
+
serialize: config.transformer.output.serialize,
|
|
359
|
+
onError: (cause)=>{
|
|
360
|
+
opts.onError?.({
|
|
361
|
+
error: getTRPCErrorFromUnknown(cause),
|
|
362
|
+
path: undefined,
|
|
363
|
+
input: undefined,
|
|
364
|
+
ctx,
|
|
365
|
+
req: opts.req,
|
|
366
|
+
type: info?.type ?? 'unknown'
|
|
367
|
+
});
|
|
368
|
+
},
|
|
369
|
+
formatError (errorOpts) {
|
|
370
|
+
const call = info?.calls[errorOpts.path[0]];
|
|
371
|
+
const shape = getErrorShape({
|
|
372
|
+
config,
|
|
373
|
+
ctx,
|
|
374
|
+
error: getTRPCErrorFromUnknown(errorOpts.error),
|
|
375
|
+
input: call?.result(),
|
|
376
|
+
path: call?.path,
|
|
377
|
+
type: call?.procedure?._def.type ?? 'unknown'
|
|
378
|
+
});
|
|
379
|
+
return shape;
|
|
270
380
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
381
|
+
});
|
|
382
|
+
return new Response(stream1, {
|
|
383
|
+
headers,
|
|
384
|
+
status: headResponse2.status
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
// httpBatchLink
|
|
388
|
+
/**
|
|
389
|
+
* Non-streaming response:
|
|
390
|
+
* - await all responses in parallel, blocking on the slowest one
|
|
391
|
+
* - create headers with known response body
|
|
392
|
+
* - return a complete HTTPResponse
|
|
393
|
+
*/ headers.set('content-type', 'application/json');
|
|
394
|
+
const results = (await Promise.all(rpcCalls)).map((res)=>{
|
|
395
|
+
const [data, error] = res;
|
|
396
|
+
if (error) {
|
|
397
|
+
return res;
|
|
283
398
|
}
|
|
399
|
+
if (isDataStream(data)) {
|
|
400
|
+
return [
|
|
401
|
+
null,
|
|
402
|
+
new TRPCError({
|
|
403
|
+
code: 'UNSUPPORTED_MEDIA_TYPE',
|
|
404
|
+
message: 'Cannot use stream-like response in non-streaming request - use httpBatchStreamLink'
|
|
405
|
+
})
|
|
406
|
+
];
|
|
407
|
+
}
|
|
408
|
+
return res;
|
|
284
409
|
});
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
410
|
+
const resultAsRPCResponse = results.map(([data, error], index)=>{
|
|
411
|
+
const call = info.calls[index];
|
|
412
|
+
if (error) {
|
|
413
|
+
return {
|
|
414
|
+
error: getErrorShape({
|
|
415
|
+
config,
|
|
416
|
+
ctx,
|
|
417
|
+
error,
|
|
418
|
+
input: call.result(),
|
|
419
|
+
path: call.path,
|
|
420
|
+
type: call.procedure?._def.type ?? 'unknown'
|
|
421
|
+
})
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
return {
|
|
425
|
+
result: {
|
|
426
|
+
data
|
|
427
|
+
}
|
|
428
|
+
};
|
|
429
|
+
});
|
|
430
|
+
const errors = results.map(([_, error])=>error).filter(Boolean);
|
|
431
|
+
const headResponse3 = initResponse({
|
|
432
|
+
ctx,
|
|
433
|
+
info,
|
|
434
|
+
responseMeta: opts.responseMeta,
|
|
435
|
+
untransformedJSON: resultAsRPCResponse,
|
|
436
|
+
errors,
|
|
437
|
+
headers
|
|
438
|
+
});
|
|
439
|
+
return new Response(JSON.stringify(transformTRPCResponse(config, resultAsRPCResponse)), {
|
|
440
|
+
status: headResponse3.status,
|
|
441
|
+
headers
|
|
288
442
|
});
|
|
289
443
|
} catch (cause) {
|
|
290
444
|
// we get here if
|
|
@@ -294,24 +448,23 @@ async function resolveResponse(opts) {
|
|
|
294
448
|
// - post body is too large
|
|
295
449
|
// - input deserialization fails
|
|
296
450
|
// - `errorFormatter` return value is malformed
|
|
297
|
-
const { error , untransformedJSON
|
|
451
|
+
const { error: error1 , untransformedJSON , body } = caughtErrorToData(cause, {
|
|
298
452
|
opts,
|
|
299
453
|
ctx,
|
|
300
|
-
type
|
|
454
|
+
type: info?.type ?? 'unknown'
|
|
301
455
|
});
|
|
302
|
-
const
|
|
456
|
+
const headResponse4 = initResponse({
|
|
303
457
|
ctx,
|
|
304
458
|
info,
|
|
305
|
-
type,
|
|
306
459
|
responseMeta: opts.responseMeta,
|
|
307
|
-
untransformedJSON
|
|
460
|
+
untransformedJSON,
|
|
308
461
|
errors: [
|
|
309
|
-
|
|
462
|
+
error1
|
|
310
463
|
],
|
|
311
464
|
headers
|
|
312
465
|
});
|
|
313
|
-
return new Response(
|
|
314
|
-
status:
|
|
466
|
+
return new Response(body, {
|
|
467
|
+
status: headResponse4.status,
|
|
315
468
|
headers
|
|
316
469
|
});
|
|
317
470
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { TRPCError } from '../error/TRPCError';
|
|
2
|
-
import type { ErrorHandlerOptions, ProcedureType } from '../procedure';
|
|
2
|
+
import type { AnyProcedure, ErrorHandlerOptions, ProcedureType } from '../procedure';
|
|
3
3
|
import type { AnyRouter, inferRouterContext, inferRouterError } from '../router';
|
|
4
4
|
import type { TRPCResponse } from '../rpc';
|
|
5
5
|
import type { Dict } from '../types';
|
|
@@ -41,6 +41,7 @@ export interface HTTPBaseHandlerOptions<TRouter extends AnyRouter, TRequest> ext
|
|
|
41
41
|
*/
|
|
42
42
|
responseMeta?: ResponseMetaFn<TRouter>;
|
|
43
43
|
}
|
|
44
|
+
export type TRPCAcceptHeader = 'application/jsonl';
|
|
44
45
|
interface TRPCRequestInfoProcedureCall {
|
|
45
46
|
path: string;
|
|
46
47
|
/**
|
|
@@ -51,15 +52,43 @@ interface TRPCRequestInfoProcedureCall {
|
|
|
51
52
|
* Get already parsed inputs - won't trigger reading the body or parsing the inputs
|
|
52
53
|
*/
|
|
53
54
|
result: () => unknown;
|
|
55
|
+
/**
|
|
56
|
+
* The procedure being called, `null` if not found
|
|
57
|
+
* @internal
|
|
58
|
+
*/
|
|
59
|
+
procedure: AnyProcedure | null;
|
|
60
|
+
}
|
|
61
|
+
export interface TRPCRequestInfoBase {
|
|
62
|
+
/**
|
|
63
|
+
* The `trpc-accept` header
|
|
64
|
+
*/
|
|
65
|
+
accept: TRPCAcceptHeader | null;
|
|
66
|
+
/**
|
|
67
|
+
* The type of the request
|
|
68
|
+
*/
|
|
69
|
+
type: ProcedureType | 'unknown';
|
|
70
|
+
/**
|
|
71
|
+
* If the content type handler has detected that this is a batch call
|
|
72
|
+
*/
|
|
73
|
+
isBatchCall: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* The calls being made
|
|
76
|
+
*/
|
|
77
|
+
calls: TRPCRequestInfoProcedureCall[];
|
|
78
|
+
}
|
|
79
|
+
interface TRPCRequestInfoBatchCall extends TRPCRequestInfoBase {
|
|
80
|
+
isBatchCall: true;
|
|
81
|
+
calls: TRPCRequestInfoProcedureCall[];
|
|
82
|
+
}
|
|
83
|
+
interface TRPCRequestInfoSingleCall extends TRPCRequestInfoBase {
|
|
84
|
+
isBatchCall: false;
|
|
85
|
+
calls: [TRPCRequestInfoProcedureCall];
|
|
54
86
|
}
|
|
55
87
|
/**
|
|
56
88
|
* Information about the incoming request
|
|
57
89
|
* @public
|
|
58
90
|
*/
|
|
59
|
-
export
|
|
60
|
-
isBatchCall: boolean;
|
|
61
|
-
calls: TRPCRequestInfoProcedureCall[];
|
|
62
|
-
}
|
|
91
|
+
export type TRPCRequestInfo = TRPCRequestInfoBatchCall | TRPCRequestInfoSingleCall;
|
|
63
92
|
/**
|
|
64
93
|
* Inner createContext function for `resolveResponse` used to forward `TRPCRequestInfo` to `createContext`
|
|
65
94
|
* @internal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/unstable-core-do-not-import/http/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/unstable-core-do-not-import/http/types.ts"],"names":[],"mappings":"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"}
|