@trpc/server 11.0.0-rc.607 → 11.0.0-rc.619

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 (36) hide show
  1. package/dist/@trpc/server/http.d.ts +1 -1
  2. package/dist/@trpc/server/http.d.ts.map +1 -1
  3. package/dist/adapters/fetch/fetchRequestHandler.js +1 -2
  4. package/dist/adapters/fetch/fetchRequestHandler.mjs +1 -2
  5. package/dist/adapters/node-http/incomingMessageToRequest.d.ts +1 -0
  6. package/dist/adapters/node-http/incomingMessageToRequest.d.ts.map +1 -1
  7. package/dist/adapters/node-http/incomingMessageToRequest.js +73 -38
  8. package/dist/adapters/node-http/incomingMessageToRequest.mjs +73 -39
  9. package/dist/adapters/node-http/index.js +1 -0
  10. package/dist/adapters/node-http/index.mjs +1 -1
  11. package/dist/adapters/standalone.d.ts.map +1 -1
  12. package/dist/adapters/standalone.js +2 -2
  13. package/dist/adapters/standalone.mjs +2 -2
  14. package/dist/adapters/ws.d.ts +1 -1
  15. package/dist/adapters/ws.d.ts.map +1 -1
  16. package/dist/adapters/ws.js +2 -2
  17. package/dist/adapters/ws.mjs +2 -2
  18. package/dist/bundle-analysis.json +94 -108
  19. package/dist/http.js +0 -2
  20. package/dist/http.mjs +0 -1
  21. package/dist/unstable-core-do-not-import.d.ts +0 -1
  22. package/dist/unstable-core-do-not-import.d.ts.map +1 -1
  23. package/dist/unstable-core-do-not-import.js +0 -2
  24. package/dist/unstable-core-do-not-import.mjs +0 -1
  25. package/package.json +2 -2
  26. package/src/@trpc/server/http.ts +0 -1
  27. package/src/adapters/fetch/fetchRequestHandler.ts +2 -2
  28. package/src/adapters/node-http/incomingMessageToRequest.ts +99 -39
  29. package/src/adapters/standalone.ts +7 -4
  30. package/src/adapters/ws.ts +3 -3
  31. package/src/unstable-core-do-not-import.ts +0 -1
  32. package/dist/unstable-core-do-not-import/http/toURL.d.ts +0 -2
  33. package/dist/unstable-core-do-not-import/http/toURL.d.ts.map +0 -1
  34. package/dist/unstable-core-do-not-import/http/toURL.js +0 -18
  35. package/dist/unstable-core-do-not-import/http/toURL.mjs +0 -16
  36. package/src/unstable-core-do-not-import/http/toURL.ts +0 -17
@@ -1,6 +1,5 @@
1
1
  import type * as http from 'http';
2
2
  import { TRPCError } from '../../@trpc/server';
3
- import { toURL } from '../../http';
4
3
 
5
4
  export interface IncomingMessageWithBody extends http.IncomingMessage {
6
5
  /**
@@ -8,52 +7,112 @@ export interface IncomingMessageWithBody extends http.IncomingMessage {
8
7
  */
9
8
  body?: unknown;
10
9
  }
11
- /**
12
- * Convert an incoming message to a body stream with a max size
13
- */
14
- function incomingMessageToBodyStream(
15
- req: IncomingMessageWithBody,
16
- opts: { maxBodySize: number | null },
17
- ) {
18
- type Value = Buffer | Uint8Array | string | null;
10
+
11
+ function createBody(
12
+ req: http.IncomingMessage,
13
+ opts: {
14
+ /**
15
+ * Max body size in bytes. If the body is larger than this, the request will be aborted
16
+ */
17
+ maxBodySize: number | null;
18
+ },
19
+ ): RequestInit['body'] {
20
+ // Some adapters will pre-parse the body and add it to the request object
21
+ if ('body' in req) {
22
+ // If the body is already a string, return it directly
23
+ if (typeof req.body === 'string') {
24
+ return req.body;
25
+ }
26
+ // If body exists but isn't a string, stringify it as JSON
27
+ else if (req.body !== undefined) {
28
+ return JSON.stringify(req.body);
29
+ }
30
+ // If body property exists but is undefined, return undefined
31
+ return undefined;
32
+ }
19
33
  let size = 0;
20
- const maxBodySize = opts.maxBodySize;
21
34
  let hasClosed = false;
22
35
 
23
- const stream = new ReadableStream<Value>({
36
+ return new ReadableStream({
24
37
  start(controller) {
25
- req.on('data', (chunk) => {
38
+ const onData = (chunk: Buffer) => {
26
39
  size += chunk.length;
27
- if (maxBodySize != null && size > maxBodySize) {
28
- controller.error(
29
- new TRPCError({
30
- code: 'PAYLOAD_TOO_LARGE',
31
- }),
40
+ if (!opts.maxBodySize || size <= opts.maxBodySize) {
41
+ controller.enqueue(
42
+ new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength),
32
43
  );
33
- // an error is thrown if we try to close the controller after
34
- // erroring, so track the closure
35
- hasClosed = true;
36
44
  return;
37
45
  }
38
- controller.enqueue(chunk);
39
- });
40
- req.once('end', () => {
46
+ controller.error(
47
+ new TRPCError({
48
+ code: 'PAYLOAD_TOO_LARGE',
49
+ }),
50
+ );
51
+ hasClosed = true;
52
+ req.off('data', onData);
53
+ req.off('end', onEnd);
54
+ };
55
+
56
+ const onEnd = () => {
41
57
  if (hasClosed) {
42
58
  return;
43
59
  }
44
60
  hasClosed = true;
61
+ req.off('data', onData);
62
+ req.off('end', onEnd);
45
63
  controller.close();
46
- });
64
+ };
65
+
66
+ req.on('data', onData);
67
+ req.on('end', onEnd);
47
68
  },
48
69
  cancel() {
49
70
  req.destroy();
50
71
  },
51
72
  });
73
+ }
74
+ export function createURL(req: http.IncomingMessage): URL {
75
+ try {
76
+ const protocol =
77
+ req.socket && 'encrypted' in req.socket && req.socket.encrypted
78
+ ? 'https:'
79
+ : 'http:';
52
80
 
53
- return stream;
81
+ const host = req.headers.host ?? 'localhost';
82
+
83
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
84
+ return new URL(req.url!, `${protocol}//${host}`);
85
+ } catch (cause) {
86
+ throw new TRPCError({
87
+ code: 'BAD_REQUEST',
88
+ message: 'Invalid URL',
89
+ cause,
90
+ });
91
+ }
92
+ }
93
+
94
+ function createHeaders(incoming: http.IncomingHttpHeaders): Headers {
95
+ const headers = new Headers();
96
+
97
+ for (const key in incoming) {
98
+ const value = incoming[key];
99
+ if (typeof key === 'string' && key.startsWith(':')) {
100
+ // Skip HTTP/2 pseudo-headers
101
+ continue;
102
+ }
103
+
104
+ if (Array.isArray(value)) {
105
+ for (const item of value) {
106
+ headers.append(key, item);
107
+ }
108
+ } else if (value != null) {
109
+ headers.append(key, value);
110
+ }
111
+ }
112
+
113
+ return headers;
54
114
  }
55
115
 
56
- const bodyMethods = ['POST', 'PUT', 'PATCH'];
57
116
  /**
58
117
  * Convert an [`IncomingMessage`](https://nodejs.org/api/http.html#class-httpincomingmessage) to a [`Request`](https://developer.mozilla.org/en-US/docs/Web/API/Request)
59
118
  */
@@ -67,29 +126,30 @@ export function incomingMessageToRequest(
67
126
  },
68
127
  ): Request {
69
128
  const ac = new AbortController();
70
- const headers = new Headers(req.headers as any);
71
- const url = toURL(`http://${headers.get('host')}${req.url}`);
72
129
  req.once('aborted', () => {
73
130
  ac.abort();
74
131
  });
75
132
 
133
+ // Get host from either regular header or HTTP/2 pseudo-header
134
+ const url = createURL(req);
135
+
76
136
  const init: RequestInit = {
77
- headers,
137
+ headers: createHeaders(req.headers),
78
138
  method: req.method,
79
139
  signal: ac.signal,
80
- // @ts-expect-error this is fine
81
- duplex: 'half',
82
140
  };
83
141
 
84
- if (req.method && bodyMethods.includes(req.method)) {
85
- if (!('body' in req)) {
86
- init.body = incomingMessageToBodyStream(req, opts);
87
- } else if (typeof req.body === 'string') {
88
- init.body = req.body;
89
- } else if (req.body !== undefined) {
90
- init.body = JSON.stringify(req.body);
91
- }
142
+ if (req.method !== 'GET' && req.method !== 'HEAD') {
143
+ init.body = createBody(req, opts);
144
+
145
+ // init.duplex = 'half' must be set when body is a ReadableStream, and Node follows the spec.
146
+ // However, this property is not defined in the TypeScript types for RequestInit, so we have
147
+ // to cast it here in order to set it without a type error.
148
+ // See https://fetch.spec.whatwg.org/#dom-requestinit-duplex
149
+ // @ts-expect-error this is fine
150
+ init.duplex = 'half';
92
151
  }
152
+
93
153
  const request = new Request(url, init);
94
154
 
95
155
  return request;
@@ -7,18 +7,21 @@
7
7
  * import type { HTTPBaseHandlerOptions } from '@trpc/server/http'
8
8
  * ```
9
9
  */
10
- /* eslint-disable @typescript-eslint/no-non-null-assertion */
10
+
11
11
  import http from 'http';
12
12
  // @trpc/server
13
13
  import { type AnyRouter } from '../@trpc/server';
14
- import { toURL } from '../@trpc/server/http';
15
14
  // eslint-disable-next-line no-restricted-imports
16
15
  import { run } from '../unstable-core-do-not-import';
17
16
  import type {
18
17
  NodeHTTPCreateContextFnOptions,
19
18
  NodeHTTPHandlerOptions,
20
19
  } from './node-http';
21
- import { internal_exceptionHandler, nodeHTTPRequestHandler } from './node-http';
20
+ import {
21
+ createURL,
22
+ internal_exceptionHandler,
23
+ nodeHTTPRequestHandler,
24
+ } from './node-http';
22
25
 
23
26
  export type CreateHTTPHandlerOptions<TRouter extends AnyRouter> =
24
27
  NodeHTTPHandlerOptions<TRouter, http.IncomingMessage, http.ServerResponse>;
@@ -37,7 +40,7 @@ export function createHTTPHandler<TRouter extends AnyRouter>(
37
40
  return (req, res) => {
38
41
  let path = '';
39
42
  run(async () => {
40
- const url = toURL(req.url!);
43
+ const url = createURL(req);
41
44
 
42
45
  // get procedure path and remove the leading slash
43
46
  // /procedure -> procedure
@@ -13,7 +13,7 @@ import {
13
13
  TRPCError,
14
14
  } from '../@trpc/server';
15
15
  import type { TRPCRequestInfo } from '../@trpc/server/http';
16
- import { toURL, type BaseHandlerOptions } from '../@trpc/server/http';
16
+ import { type BaseHandlerOptions } from '../@trpc/server/http';
17
17
  import { parseTRPCMessage } from '../@trpc/server/rpc';
18
18
  // @trpc/server/rpc
19
19
  import type {
@@ -34,7 +34,7 @@ import {
34
34
  type MaybePromise,
35
35
  } from '../unstable-core-do-not-import';
36
36
  import { Unpromise } from '../vendor/unpromise';
37
- import type { NodeHTTPCreateContextFnOptions } from './node-http';
37
+ import { createURL, type NodeHTTPCreateContextFnOptions } from './node-http';
38
38
 
39
39
  /**
40
40
  * Importing ws causes a build error
@@ -178,7 +178,7 @@ export function getWSConnectionHandler<TRouter extends AnyRouter>(
178
178
  * - if connection params are expected, they will be created once received
179
179
  */
180
180
  let ctxPromise =
181
- toURL(req.url ?? '').searchParams.get('connectionParams') === '1'
181
+ createURL(req).searchParams.get('connectionParams') === '1'
182
182
  ? unsetContextPromiseSymbol
183
183
  : createCtxPromise(() => null);
184
184
 
@@ -22,7 +22,6 @@ export * from './unstable-core-do-not-import/http/formDataToObject';
22
22
  export * from './unstable-core-do-not-import/http/getHTTPStatusCode';
23
23
  export * from './unstable-core-do-not-import/http/parseConnectionParams';
24
24
  export * from './unstable-core-do-not-import/http/resolveResponse';
25
- export * from './unstable-core-do-not-import/http/toURL';
26
25
  export * from './unstable-core-do-not-import/http/types';
27
26
  export * from './unstable-core-do-not-import/initTRPC';
28
27
  export * from './unstable-core-do-not-import/middleware';
@@ -1,2 +0,0 @@
1
- export declare function toURL(urlOrPathname: string): URL;
2
- //# sourceMappingURL=toURL.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"toURL.d.ts","sourceRoot":"","sources":["../../../src/unstable-core-do-not-import/http/toURL.ts"],"names":[],"mappings":"AAEA,wBAAgB,KAAK,CAAC,aAAa,EAAE,MAAM,GAAG,GAAG,CAchD"}
@@ -1,18 +0,0 @@
1
- 'use strict';
2
-
3
- var TRPCError = require('../error/TRPCError.js');
4
-
5
- function toURL(urlOrPathname) {
6
- try {
7
- const url = urlOrPathname.startsWith('/') ? `http://127.0.0.1${urlOrPathname}` : urlOrPathname;
8
- return new URL(url);
9
- } catch (cause) {
10
- throw new TRPCError.TRPCError({
11
- code: 'BAD_REQUEST',
12
- message: 'Invalid URL',
13
- cause
14
- });
15
- }
16
- }
17
-
18
- exports.toURL = toURL;
@@ -1,16 +0,0 @@
1
- import { TRPCError } from '../error/TRPCError.mjs';
2
-
3
- function toURL(urlOrPathname) {
4
- try {
5
- const url = urlOrPathname.startsWith('/') ? `http://127.0.0.1${urlOrPathname}` : urlOrPathname;
6
- return new URL(url);
7
- } catch (cause) {
8
- throw new TRPCError({
9
- code: 'BAD_REQUEST',
10
- message: 'Invalid URL',
11
- cause
12
- });
13
- }
14
- }
15
-
16
- export { toURL };
@@ -1,17 +0,0 @@
1
- import { TRPCError } from '../error/TRPCError';
2
-
3
- export function toURL(urlOrPathname: string): URL {
4
- try {
5
- const url = urlOrPathname.startsWith('/')
6
- ? `http://127.0.0.1${urlOrPathname}`
7
- : urlOrPathname;
8
-
9
- return new URL(url);
10
- } catch (cause) {
11
- throw new TRPCError({
12
- code: 'BAD_REQUEST',
13
- message: 'Invalid URL',
14
- cause,
15
- });
16
- }
17
- }