@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.
Files changed (95) hide show
  1. package/dist/@trpc/server/index.d.ts +1 -1
  2. package/dist/@trpc/server/index.d.ts.map +1 -1
  3. package/dist/adapters/aws-lambda/getPlanner.d.ts.map +1 -1
  4. package/dist/adapters/next-app-dir/redirect.d.ts.map +1 -1
  5. package/dist/adapters/node-http/incomingMessageToRequest.d.ts +0 -1
  6. package/dist/adapters/node-http/incomingMessageToRequest.d.ts.map +1 -1
  7. package/dist/adapters/node-http/incomingMessageToRequest.js +3 -1
  8. package/dist/adapters/node-http/incomingMessageToRequest.mjs +3 -1
  9. package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +1 -1
  10. package/dist/adapters/node-http/nodeHTTPRequestHandler.js +30 -7
  11. package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +30 -7
  12. package/dist/adapters/node-http/types.d.ts +0 -1
  13. package/dist/adapters/node-http/types.d.ts.map +1 -1
  14. package/dist/adapters/standalone.d.ts +0 -1
  15. package/dist/adapters/standalone.d.ts.map +1 -1
  16. package/dist/adapters/ws.d.ts +1 -2
  17. package/dist/adapters/ws.d.ts.map +1 -1
  18. package/dist/adapters/ws.js +98 -81
  19. package/dist/adapters/ws.mjs +98 -81
  20. package/dist/bundle-analysis.json +183 -124
  21. package/dist/index.js +5 -3
  22. package/dist/index.mjs +2 -1
  23. package/dist/observable/observable.d.ts +1 -0
  24. package/dist/observable/observable.d.ts.map +1 -1
  25. package/dist/observable/observable.js +55 -0
  26. package/dist/observable/observable.mjs +55 -1
  27. package/dist/unstable-core-do-not-import/createProxy.d.ts.map +1 -1
  28. package/dist/unstable-core-do-not-import/http/contentType.d.ts +7 -4
  29. package/dist/unstable-core-do-not-import/http/contentType.d.ts.map +1 -1
  30. package/dist/unstable-core-do-not-import/http/contentType.js +55 -17
  31. package/dist/unstable-core-do-not-import/http/contentType.mjs +56 -18
  32. package/dist/unstable-core-do-not-import/http/resolveResponse.d.ts.map +1 -1
  33. package/dist/unstable-core-do-not-import/http/resolveResponse.js +302 -149
  34. package/dist/unstable-core-do-not-import/http/resolveResponse.mjs +301 -148
  35. package/dist/unstable-core-do-not-import/http/types.d.ts +34 -5
  36. package/dist/unstable-core-do-not-import/http/types.d.ts.map +1 -1
  37. package/dist/unstable-core-do-not-import/initTRPC.d.ts +12 -12
  38. package/dist/unstable-core-do-not-import/initTRPC.d.ts.map +1 -1
  39. package/dist/unstable-core-do-not-import/middleware.d.ts +3 -3
  40. package/dist/unstable-core-do-not-import/middleware.d.ts.map +1 -1
  41. package/dist/unstable-core-do-not-import/procedureBuilder.d.ts +3 -1
  42. package/dist/unstable-core-do-not-import/procedureBuilder.d.ts.map +1 -1
  43. package/dist/unstable-core-do-not-import/rootConfig.d.ts +12 -0
  44. package/dist/unstable-core-do-not-import/rootConfig.d.ts.map +1 -1
  45. package/dist/unstable-core-do-not-import/router.d.ts +2 -2
  46. package/dist/unstable-core-do-not-import/router.d.ts.map +1 -1
  47. package/dist/unstable-core-do-not-import/router.js +6 -0
  48. package/dist/unstable-core-do-not-import/router.mjs +6 -0
  49. package/dist/unstable-core-do-not-import/stream/{stream.d.ts → jsonl.d.ts} +5 -5
  50. package/dist/unstable-core-do-not-import/stream/jsonl.d.ts.map +1 -0
  51. package/dist/unstable-core-do-not-import/stream/{stream.js → jsonl.js} +90 -89
  52. package/dist/unstable-core-do-not-import/stream/{stream.mjs → jsonl.mjs} +89 -88
  53. package/dist/unstable-core-do-not-import/stream/sse.d.ts +86 -0
  54. package/dist/unstable-core-do-not-import/stream/sse.d.ts.map +1 -0
  55. package/dist/unstable-core-do-not-import/stream/sse.js +178 -0
  56. package/dist/unstable-core-do-not-import/stream/sse.mjs +172 -0
  57. package/dist/unstable-core-do-not-import/stream/utils/createDeferred.d.ts +18 -0
  58. package/dist/unstable-core-do-not-import/stream/utils/createDeferred.d.ts.map +1 -0
  59. package/dist/unstable-core-do-not-import/stream/utils/createDeferred.js +46 -0
  60. package/dist/unstable-core-do-not-import/stream/utils/createDeferred.mjs +43 -0
  61. package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts +10 -0
  62. package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.d.ts.map +1 -0
  63. package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.js +31 -0
  64. package/dist/unstable-core-do-not-import/stream/utils/createReadableStream.mjs +29 -0
  65. package/dist/unstable-core-do-not-import/stream/utils/createServer.d.ts +7 -0
  66. package/dist/unstable-core-do-not-import/stream/utils/createServer.d.ts.map +1 -0
  67. package/dist/unstable-core-do-not-import/transformer.d.ts +5 -5
  68. package/dist/unstable-core-do-not-import/utils.d.ts +4 -0
  69. package/dist/unstable-core-do-not-import/utils.d.ts.map +1 -1
  70. package/dist/unstable-core-do-not-import/utils.js +4 -0
  71. package/dist/unstable-core-do-not-import/utils.mjs +4 -1
  72. package/dist/unstable-core-do-not-import.d.ts +2 -1
  73. package/dist/unstable-core-do-not-import.d.ts.map +1 -1
  74. package/dist/unstable-core-do-not-import.js +11 -4
  75. package/dist/unstable-core-do-not-import.mjs +3 -2
  76. package/package.json +3 -3
  77. package/src/@trpc/server/index.ts +1 -0
  78. package/src/adapters/node-http/incomingMessageToRequest.ts +3 -2
  79. package/src/adapters/node-http/nodeHTTPRequestHandler.ts +32 -7
  80. package/src/adapters/ws.ts +101 -75
  81. package/src/observable/observable.ts +63 -0
  82. package/src/unstable-core-do-not-import/http/contentType.ts +78 -21
  83. package/src/unstable-core-do-not-import/http/resolveResponse.ts +331 -164
  84. package/src/unstable-core-do-not-import/http/types.ts +42 -5
  85. package/src/unstable-core-do-not-import/procedureBuilder.ts +8 -1
  86. package/src/unstable-core-do-not-import/rootConfig.ts +12 -0
  87. package/src/unstable-core-do-not-import/router.ts +12 -0
  88. package/src/unstable-core-do-not-import/stream/{stream.ts → jsonl.ts} +99 -85
  89. package/src/unstable-core-do-not-import/stream/sse.ts +288 -0
  90. package/src/unstable-core-do-not-import/stream/utils/createDeferred.ts +48 -0
  91. package/src/unstable-core-do-not-import/stream/utils/createReadableStream.ts +31 -0
  92. package/src/unstable-core-do-not-import/stream/utils/createServer.ts +46 -0
  93. package/src/unstable-core-do-not-import/utils.ts +5 -0
  94. package/src/unstable-core-do-not-import.ts +2 -1
  95. 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 { callProcedure } from '../router.mjs';
4
- import { isPromise, jsonlStreamProducer } from '../stream/stream.mjs';
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 HTTP_METHOD_PROCEDURE_TYPE_MAP = {
11
- GET: 'query',
12
- POST: 'mutation'
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 , type , responseMeta , untransformedJSON , errors =[] , headers , } = initOpts;
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 isStreamCall = req.headers.get('trpc-accept') === 'application/jsonl';
107
- const experimentalIterablesAndDeferreds = config.experimental?.iterablesAndDeferreds ?? false;
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
- config: config,
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 (type === 'unknown') {
167
+ /* istanbul ignore if -- @preserve */ if (isStreamCall && !info.isBatchCall) {
129
168
  throw new TRPCError({
130
- message: `Unexpected request method ${req.method}`,
131
- code: 'METHOD_NOT_SUPPORTED'
169
+ message: `Streaming requests must be batched (you can do a batch of 1)`,
170
+ code: 'BAD_REQUEST'
132
171
  });
133
172
  }
134
- const errors = [];
135
- const promises = info.calls.map(async (call)=>{
173
+ const rpcCalls = info.calls.map(async (call)=>{
174
+ const proc = call.procedure;
136
175
  try {
137
- const data = await callProcedure({
138
- procedures: opts.router._def.procedures,
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
- if ((!isStreamCall || !experimentalIterablesAndDeferreds) && isObject(data) && (Symbol.asyncIterator in data || Object.values(data).some(isPromise))) {
146
- if (!isStreamCall) {
147
- throw new TRPCError({
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
- error: getErrorShape({
178
- config,
179
- error,
180
- type,
181
- path: call.path,
182
- input,
183
- ctx
184
- })
185
- };
214
+ return [
215
+ null,
216
+ error
217
+ ];
186
218
  }
187
219
  });
188
- if (!isStreamCall) {
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
- * Non-streaming response:
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
- untransformedJSON,
205
- errors: errors1,
206
- headers
315
+ errors: [],
316
+ headers,
317
+ untransformedJSON: null
207
318
  });
208
- // return body stuff
209
- const result = info.isBatchCall ? untransformedJSON : untransformedJSON[0];
210
- const transformedJSON = transformTRPCResponse(router._def._config, result);
211
- const body = JSON.stringify(transformedJSON);
212
- return new Response(body, {
213
- status: headResponse.status,
214
- headers
215
- });
216
- }
217
- headers.set('content-type', 'application/json');
218
- headers.set('transfer-encoding', 'chunked');
219
- /**
220
- * Streaming response:
221
- * - block on none, call `onChunk` as soon as each response is ready
222
- * - create headers with minimal data (cannot know the response body in advance)
223
- * - return void
224
- */ const headResponse1 = initResponse({
225
- ctx,
226
- info,
227
- type,
228
- responseMeta: opts.responseMeta,
229
- errors: [],
230
- headers
231
- });
232
- const stream = jsonlStreamProducer({
233
- /**
234
- * Example structure for `maxDepth: 4`:
235
- * {
236
- * // 1
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
- */ return {
264
- ...response,
351
+ */ const data = isObservable(result) ? observableToAsyncIterable(result) : Promise.resolve(result);
352
+ return {
265
353
  result: Promise.resolve({
266
- ...response.result,
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
- return response;
272
- }),
273
- serialize: config.transformer.output.serialize,
274
- onError: (cause)=>{
275
- opts.onError?.({
276
- error: getTRPCErrorFromUnknown(cause),
277
- path: undefined,
278
- input: undefined,
279
- ctx,
280
- type,
281
- req: opts.req
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
- return new Response(stream, {
286
- headers,
287
- status: headResponse1.status
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: untransformedJSON1 , body: body1 } = caughtErrorToData(cause, {
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 headResponse2 = initResponse({
456
+ const headResponse4 = initResponse({
303
457
  ctx,
304
458
  info,
305
- type,
306
459
  responseMeta: opts.responseMeta,
307
- untransformedJSON: untransformedJSON1,
460
+ untransformedJSON,
308
461
  errors: [
309
- error
462
+ error1
310
463
  ],
311
464
  headers
312
465
  });
313
- return new Response(body1, {
314
- status: headResponse2.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 interface TRPCRequestInfo {
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,EAAE,mBAAmB,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,KAAK,EACV,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC;;GAEG;AACH,KAAK,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,OAAO,SAAS,SAAS,IAAI,CAAC,IAAI,EAAE;IAC7D,IAAI,EAAE,YAAY,CAAC,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;IACzD,GAAG,CAAC,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAClC;;;QAGI;IACJ,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,eAAe,GAAG,SAAS,CAAC;IAClC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;;OAEG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B,KAAK,YAAY,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,OAAO,SAAS,SAAS,EAAE,QAAQ,CACzE,SAAQ,kBAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC7C;;;;OAIG;IACH,YAAY,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;CACxC;AAED,UAAU,4BAA4B;IACpC,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,WAAW,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC;;OAEG;IACH,MAAM,EAAE,MAAM,OAAO,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,OAAO,CAAC;IACrB,KAAK,EAAE,4BAA4B,EAAE,CAAC;CACvC;AAED;;;GAGG;AACH,MAAM,MAAM,kCAAkC,CAAC,OAAO,SAAS,SAAS,IACtE,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;AAE5E,UAAU,uBAAuB,CAAC,OAAO,SAAS,SAAS,EAAE,QAAQ,CACnE,SAAQ,mBAAmB,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACxD,GAAG,EAAE,QAAQ,CAAC;CACf;AACD;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,OAAO,SAAS,SAAS,EAAE,QAAQ,IAAI,CAClE,IAAI,EAAE,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,KAC7C,IAAI,CAAC;AAEV;;;GAGG;AACH,MAAM,WAAW,kBAAkB,CAAC,OAAO,SAAS,SAAS,EAAE,QAAQ;IACrE,OAAO,CAAC,EAAE,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C;;OAEG;IACH,QAAQ,CAAC,EAAE;QACT;;WAEG;QACH,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB"}
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,EACV,YAAY,EACZ,mBAAmB,EACnB,aAAa,EACd,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,SAAS,EACT,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,WAAW,CAAC;AACnB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC;;GAEG;AACH,KAAK,WAAW,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;AAE3C,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,GAAG,WAAW,CAAC;CACjC;AAED;;GAEG;AACH,MAAM,MAAM,cAAc,CAAC,OAAO,SAAS,SAAS,IAAI,CAAC,IAAI,EAAE;IAC7D,IAAI,EAAE,YAAY,CAAC,OAAO,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;IACzD,GAAG,CAAC,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC;IAClC;;;QAGI;IACJ,KAAK,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,eAAe,GAAG,SAAS,CAAC;IAClC,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;IAChC,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;;OAEG;IACH,eAAe,EAAE,OAAO,CAAC;CAC1B,KAAK,YAAY,CAAC;AAEnB;;GAEG;AACH,MAAM,WAAW,sBAAsB,CAAC,OAAO,SAAS,SAAS,EAAE,QAAQ,CACzE,SAAQ,kBAAkB,CAAC,OAAO,EAAE,QAAQ,CAAC;IAC7C;;;;OAIG;IACH,YAAY,CAAC,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAEnD,UAAU,4BAA4B;IACpC,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,WAAW,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACpC;;OAEG;IACH,MAAM,EAAE,MAAM,OAAO,CAAC;IACtB;;;OAGG;IACH,SAAS,EAAE,YAAY,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC;;OAEG;IACH,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC;;OAEG;IACH,IAAI,EAAE,aAAa,GAAG,SAAS,CAAC;IAChC;;OAEG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,KAAK,EAAE,4BAA4B,EAAE,CAAC;CACvC;AACD,UAAU,wBAAyB,SAAQ,mBAAmB;IAC5D,WAAW,EAAE,IAAI,CAAC;IAClB,KAAK,EAAE,4BAA4B,EAAE,CAAC;CACvC;AACD,UAAU,yBAA0B,SAAQ,mBAAmB;IAC7D,WAAW,EAAE,KAAK,CAAC;IACnB,KAAK,EAAE,CAAC,4BAA4B,CAAC,CAAC;CACvC;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB,wBAAwB,GACxB,yBAAyB,CAAC;AAE9B;;;GAGG;AACH,MAAM,MAAM,kCAAkC,CAAC,OAAO,SAAS,SAAS,IACtE,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,KAAK,OAAO,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;AAE5E,UAAU,uBAAuB,CAAC,OAAO,SAAS,SAAS,EAAE,QAAQ,CACnE,SAAQ,mBAAmB,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACxD,GAAG,EAAE,QAAQ,CAAC;CACf;AACD;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,OAAO,SAAS,SAAS,EAAE,QAAQ,IAAI,CAClE,IAAI,EAAE,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,KAC7C,IAAI,CAAC;AAEV;;;GAGG;AACH,MAAM,WAAW,kBAAkB,CAAC,OAAO,SAAS,SAAS,EAAE,QAAQ;IACrE,OAAO,CAAC,EAAE,gBAAgB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C;;OAEG;IACH,QAAQ,CAAC,EAAE;QACT;;WAEG;QACH,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;IACF,MAAM,EAAE,OAAO,CAAC;IAChB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB"}