@trpc/server 11.0.0-rc.566 → 11.0.0-rc.567
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/express.js +4 -4
- package/dist/adapters/express.mjs +4 -4
- package/dist/adapters/next.d.ts.map +1 -1
- package/dist/adapters/next.js +26 -32
- package/dist/adapters/next.mjs +27 -33
- package/dist/adapters/node-http/incomingMessageToRequest.d.ts.map +1 -1
- package/dist/adapters/node-http/incomingMessageToRequest.js +2 -1
- package/dist/adapters/node-http/incomingMessageToRequest.mjs +2 -1
- package/dist/adapters/node-http/index.js +1 -0
- package/dist/adapters/node-http/index.mjs +1 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts +5 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.d.ts.map +1 -1
- package/dist/adapters/node-http/nodeHTTPRequestHandler.js +91 -56
- package/dist/adapters/node-http/nodeHTTPRequestHandler.mjs +91 -57
- package/dist/adapters/standalone.d.ts +5 -2
- package/dist/adapters/standalone.d.ts.map +1 -1
- package/dist/adapters/standalone.js +25 -14
- package/dist/adapters/standalone.mjs +26 -15
- package/dist/bundle-analysis.json +113 -108
- package/dist/unstable-core-do-not-import/http/toURL.d.ts.map +1 -1
- package/dist/unstable-core-do-not-import/http/toURL.js +12 -2
- package/dist/unstable-core-do-not-import/http/toURL.mjs +12 -2
- package/package.json +2 -2
- package/src/adapters/express.ts +4 -4
- package/src/adapters/next.ts +33 -35
- package/src/adapters/node-http/incomingMessageToRequest.ts +2 -1
- package/src/adapters/node-http/nodeHTTPRequestHandler.ts +109 -62
- package/src/adapters/standalone.ts +32 -16
- package/src/unstable-core-do-not-import/http/toURL.ts +14 -4
package/src/adapters/express.ts
CHANGED
|
@@ -23,14 +23,14 @@ export type CreateExpressContextOptions = NodeHTTPCreateContextFnOptions<
|
|
|
23
23
|
export function createExpressMiddleware<TRouter extends AnyRouter>(
|
|
24
24
|
opts: NodeHTTPHandlerOptions<TRouter, express.Request, express.Response>,
|
|
25
25
|
): express.Handler {
|
|
26
|
-
return
|
|
27
|
-
const
|
|
26
|
+
return (req, res) => {
|
|
27
|
+
const path = req.path.slice(1);
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
nodeHTTPRequestHandler({
|
|
30
30
|
...(opts as any),
|
|
31
31
|
req,
|
|
32
32
|
res,
|
|
33
|
-
path
|
|
33
|
+
path,
|
|
34
34
|
});
|
|
35
35
|
};
|
|
36
36
|
}
|
package/src/adapters/next.ts
CHANGED
|
@@ -11,12 +11,14 @@ import type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
|
|
|
11
11
|
// @trpc/server
|
|
12
12
|
import type { AnyRouter } from '../@trpc/server';
|
|
13
13
|
// @trpc/server
|
|
14
|
-
import {
|
|
14
|
+
import { TRPCError } from '../@trpc/server';
|
|
15
|
+
// eslint-disable-next-line no-restricted-imports
|
|
16
|
+
import { run } from '../unstable-core-do-not-import';
|
|
15
17
|
import type {
|
|
16
18
|
NodeHTTPCreateContextFnOptions,
|
|
17
19
|
NodeHTTPHandlerOptions,
|
|
18
20
|
} from './node-http';
|
|
19
|
-
import { nodeHTTPRequestHandler } from './node-http';
|
|
21
|
+
import { internal_exceptionHandler, nodeHTTPRequestHandler } from './node-http';
|
|
20
22
|
|
|
21
23
|
export type CreateNextContextOptions = NodeHTTPCreateContextFnOptions<
|
|
22
24
|
NextApiRequest,
|
|
@@ -28,47 +30,43 @@ export type CreateNextContextOptions = NodeHTTPCreateContextFnOptions<
|
|
|
28
30
|
*/
|
|
29
31
|
export type { NextApiHandler, NextApiRequest, NextApiResponse } from 'next';
|
|
30
32
|
|
|
33
|
+
type SyncNextApiHandler = (req: NextApiRequest, res: NextApiResponse) => void;
|
|
34
|
+
|
|
31
35
|
export function createNextApiHandler<TRouter extends AnyRouter>(
|
|
32
36
|
opts: NodeHTTPHandlerOptions<TRouter, NextApiRequest, NextApiResponse>,
|
|
33
37
|
): NextApiHandler {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if (path === null) {
|
|
47
|
-
const error = getErrorShape({
|
|
48
|
-
config: opts.router._def._config,
|
|
49
|
-
error: new TRPCError({
|
|
38
|
+
let path = '';
|
|
39
|
+
const handler: SyncNextApiHandler = (req, res) => {
|
|
40
|
+
try {
|
|
41
|
+
path = run(() => {
|
|
42
|
+
if (typeof req.query['trpc'] === 'string') {
|
|
43
|
+
return req.query['trpc'];
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(req.query['trpc'])) {
|
|
46
|
+
return req.query['trpc'].join('/');
|
|
47
|
+
}
|
|
48
|
+
throw new TRPCError({
|
|
50
49
|
message:
|
|
51
50
|
'Query "trpc" not found - is the file named `[trpc]`.ts or `[...trpc].ts`?',
|
|
52
51
|
code: 'INTERNAL_SERVER_ERROR',
|
|
53
|
-
})
|
|
54
|
-
type: 'unknown',
|
|
55
|
-
ctx: undefined,
|
|
56
|
-
path: undefined,
|
|
57
|
-
input: undefined,
|
|
52
|
+
});
|
|
58
53
|
});
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
54
|
+
|
|
55
|
+
nodeHTTPRequestHandler({
|
|
56
|
+
...(opts as any),
|
|
57
|
+
req,
|
|
58
|
+
res,
|
|
59
|
+
path,
|
|
63
60
|
});
|
|
64
|
-
|
|
61
|
+
} catch (cause) {
|
|
62
|
+
internal_exceptionHandler({
|
|
63
|
+
req,
|
|
64
|
+
res,
|
|
65
|
+
path,
|
|
66
|
+
...opts,
|
|
67
|
+
})(cause);
|
|
65
68
|
}
|
|
66
|
-
|
|
67
|
-
await nodeHTTPRequestHandler({
|
|
68
|
-
...(opts as any),
|
|
69
|
-
req,
|
|
70
|
-
res,
|
|
71
|
-
path,
|
|
72
|
-
});
|
|
73
69
|
};
|
|
70
|
+
|
|
71
|
+
return handler;
|
|
74
72
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type * as http from 'http';
|
|
2
2
|
import { TRPCError } from '../../@trpc/server';
|
|
3
|
+
import { toURL } from '../../http';
|
|
3
4
|
|
|
4
5
|
export interface IncomingMessageWithBody extends http.IncomingMessage {
|
|
5
6
|
/**
|
|
@@ -67,7 +68,7 @@ export function incomingMessageToRequest(
|
|
|
67
68
|
): Request {
|
|
68
69
|
const ac = new AbortController();
|
|
69
70
|
const headers = new Headers(req.headers as any);
|
|
70
|
-
const url = `http://${headers.get('host')}${req.url}
|
|
71
|
+
const url = toURL(`http://${headers.get('host')}${req.url}`);
|
|
71
72
|
req.once('aborted', () => {
|
|
72
73
|
ac.abort();
|
|
73
74
|
});
|
|
@@ -10,9 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
// @trpc/server
|
|
12
12
|
|
|
13
|
-
import {
|
|
13
|
+
import {
|
|
14
|
+
getTRPCErrorFromUnknown,
|
|
15
|
+
transformTRPCResponse,
|
|
16
|
+
type AnyRouter,
|
|
17
|
+
} from '../../@trpc/server';
|
|
14
18
|
import type { ResolveHTTPRequestOptionsContextFn } from '../../@trpc/server/http';
|
|
15
19
|
import { resolveResponse } from '../../@trpc/server/http';
|
|
20
|
+
// eslint-disable-next-line no-restricted-imports
|
|
21
|
+
import { getErrorShape, run } from '../../unstable-core-do-not-import';
|
|
16
22
|
import { incomingMessageToRequest } from './incomingMessageToRequest';
|
|
17
23
|
import type {
|
|
18
24
|
NodeHTTPRequest,
|
|
@@ -20,84 +26,125 @@ import type {
|
|
|
20
26
|
NodeHTTPResponse,
|
|
21
27
|
} from './types';
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
/**
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export function internal_exceptionHandler<
|
|
24
33
|
TRouter extends AnyRouter,
|
|
25
34
|
TRequest extends NodeHTTPRequest,
|
|
26
35
|
TResponse extends NodeHTTPResponse,
|
|
27
36
|
>(opts: NodeHTTPRequestHandlerOptions<TRouter, TRequest, TResponse>) {
|
|
28
|
-
|
|
37
|
+
return (cause: unknown) => {
|
|
38
|
+
const { res, req } = opts;
|
|
39
|
+
const error = getTRPCErrorFromUnknown(cause);
|
|
29
40
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
41
|
+
const shape = getErrorShape({
|
|
42
|
+
config: opts.router._def._config,
|
|
43
|
+
error,
|
|
44
|
+
type: 'unknown',
|
|
45
|
+
path: undefined,
|
|
46
|
+
input: undefined,
|
|
47
|
+
ctx: undefined,
|
|
33
48
|
});
|
|
34
49
|
|
|
35
|
-
|
|
36
|
-
const createContext: ResolveHTTPRequestOptionsContextFn<TRouter> = async (
|
|
37
|
-
innerOpts,
|
|
38
|
-
) => {
|
|
39
|
-
return await opts.createContext?.({
|
|
40
|
-
...opts,
|
|
41
|
-
...innerOpts,
|
|
42
|
-
});
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
const response = await resolveResponse({
|
|
46
|
-
...opts,
|
|
50
|
+
opts.onError?.({
|
|
47
51
|
req,
|
|
48
|
-
error
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
error,
|
|
53
|
+
type: 'unknown',
|
|
54
|
+
path: undefined,
|
|
55
|
+
input: undefined,
|
|
56
|
+
ctx: undefined,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const transformed = transformTRPCResponse(opts.router._def._config, {
|
|
60
|
+
error: shape,
|
|
56
61
|
});
|
|
57
62
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
63
|
+
res.statusCode = shape.data.httpStatus;
|
|
64
|
+
res.end(JSON.stringify(transformed));
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function nodeHTTPRequestHandler<
|
|
69
|
+
TRouter extends AnyRouter,
|
|
70
|
+
TRequest extends NodeHTTPRequest,
|
|
71
|
+
TResponse extends NodeHTTPResponse,
|
|
72
|
+
>(opts: NodeHTTPRequestHandlerOptions<TRouter, TRequest, TResponse>) {
|
|
73
|
+
const handleViaMiddleware = opts.middleware ?? ((_req, _res, next) => next());
|
|
74
|
+
|
|
75
|
+
return handleViaMiddleware(opts.req, opts.res, (err: unknown) => {
|
|
76
|
+
run(async () => {
|
|
77
|
+
const req = incomingMessageToRequest(opts.req, {
|
|
78
|
+
maxBodySize: opts.maxBodySize ?? null,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Build tRPC dependencies
|
|
82
|
+
const createContext: ResolveHTTPRequestOptionsContextFn<TRouter> = async (
|
|
83
|
+
innerOpts,
|
|
84
|
+
) => {
|
|
85
|
+
return await opts.createContext?.({
|
|
86
|
+
...opts,
|
|
87
|
+
...innerOpts,
|
|
72
88
|
});
|
|
73
89
|
};
|
|
74
|
-
req.signal.addEventListener('abort', onAbort, {
|
|
75
|
-
once: true,
|
|
76
|
-
});
|
|
77
90
|
|
|
78
|
-
|
|
79
|
-
|
|
91
|
+
const response = await resolveResponse({
|
|
92
|
+
...opts,
|
|
93
|
+
req,
|
|
94
|
+
error: err ? getTRPCErrorFromUnknown(err) : null,
|
|
95
|
+
createContext,
|
|
96
|
+
onError(o) {
|
|
97
|
+
opts?.onError?.({
|
|
98
|
+
...o,
|
|
99
|
+
req: opts.req,
|
|
100
|
+
});
|
|
101
|
+
},
|
|
102
|
+
});
|
|
80
103
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
const { res } = opts;
|
|
105
|
+
if (res.statusCode === 200) {
|
|
106
|
+
// if the status code is set, we assume that it's been manually overridden
|
|
107
|
+
res.statusCode = response.status;
|
|
108
|
+
}
|
|
109
|
+
for (const [key, value] of response.headers) {
|
|
110
|
+
res.setHeader(key, value);
|
|
111
|
+
}
|
|
112
|
+
if (response.body) {
|
|
113
|
+
const reader = response.body.getReader();
|
|
114
|
+
const onAbort = () => {
|
|
115
|
+
// cancelling the reader will cause the whole stream to be cancelled
|
|
116
|
+
reader.cancel().catch(() => {
|
|
117
|
+
// console.error('reader.cancel() error', err);
|
|
90
118
|
});
|
|
91
|
-
}
|
|
119
|
+
};
|
|
120
|
+
req.signal.addEventListener('abort', onAbort, {
|
|
121
|
+
once: true,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
while (true) {
|
|
125
|
+
const { done, value } = await reader.read();
|
|
92
126
|
|
|
93
|
-
|
|
94
|
-
|
|
127
|
+
if (done) {
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
if (!res.writable) {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
if (res.write(value) === false) {
|
|
134
|
+
await new Promise<void>((resolve) => {
|
|
135
|
+
res.once('drain', resolve);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
95
138
|
|
|
96
|
-
|
|
97
|
-
|
|
139
|
+
// useful for debugging chunked responses:
|
|
140
|
+
// console.log('wrote', Buffer.from(value).toString());
|
|
141
|
+
|
|
142
|
+
// IMPORTANT - flush the response buffer, otherwise the client will not receive the data until `.end()`
|
|
143
|
+
res.flush?.();
|
|
144
|
+
}
|
|
145
|
+
req.signal.removeEventListener('abort', onAbort);
|
|
98
146
|
}
|
|
99
|
-
|
|
100
|
-
}
|
|
101
|
-
res.end();
|
|
147
|
+
res.end();
|
|
148
|
+
}).catch(internal_exceptionHandler(opts));
|
|
102
149
|
});
|
|
103
150
|
}
|
|
@@ -10,13 +10,13 @@
|
|
|
10
10
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
11
11
|
import http from 'http';
|
|
12
12
|
// @trpc/server
|
|
13
|
-
import type
|
|
13
|
+
import { type AnyRouter } from '../@trpc/server';
|
|
14
14
|
import { toURL } from '../@trpc/server/http';
|
|
15
15
|
import type {
|
|
16
16
|
NodeHTTPCreateContextFnOptions,
|
|
17
17
|
NodeHTTPHandlerOptions,
|
|
18
18
|
} from './node-http';
|
|
19
|
-
import { nodeHTTPRequestHandler } from './node-http';
|
|
19
|
+
import { internal_exceptionHandler, nodeHTTPRequestHandler } from './node-http';
|
|
20
20
|
|
|
21
21
|
export type CreateHTTPHandlerOptions<TRouter extends AnyRouter> =
|
|
22
22
|
NodeHTTPHandlerOptions<TRouter, http.IncomingMessage, http.ServerResponse>;
|
|
@@ -26,28 +26,44 @@ export type CreateHTTPContextOptions = NodeHTTPCreateContextFnOptions<
|
|
|
26
26
|
http.ServerResponse
|
|
27
27
|
>;
|
|
28
28
|
|
|
29
|
+
/**
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
29
32
|
export function createHTTPHandler<TRouter extends AnyRouter>(
|
|
30
33
|
opts: CreateHTTPHandlerOptions<TRouter>,
|
|
31
|
-
) {
|
|
32
|
-
return
|
|
33
|
-
|
|
34
|
+
): http.RequestListener {
|
|
35
|
+
return (req, res) => {
|
|
36
|
+
let path = '';
|
|
37
|
+
try {
|
|
38
|
+
const url = toURL(req.url!);
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
// get procedure path and remove the leading slash
|
|
41
|
+
// /procedure -> procedure
|
|
42
|
+
path = url.pathname.slice(1);
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
44
|
+
nodeHTTPRequestHandler({
|
|
45
|
+
...(opts as any),
|
|
46
|
+
req,
|
|
47
|
+
res,
|
|
48
|
+
path,
|
|
49
|
+
});
|
|
50
|
+
} catch (cause) {
|
|
51
|
+
internal_exceptionHandler<
|
|
52
|
+
TRouter,
|
|
53
|
+
http.IncomingMessage,
|
|
54
|
+
http.ServerResponse
|
|
55
|
+
>({
|
|
56
|
+
req,
|
|
57
|
+
res,
|
|
58
|
+
path,
|
|
59
|
+
...opts,
|
|
60
|
+
})(cause);
|
|
61
|
+
}
|
|
45
62
|
};
|
|
46
63
|
}
|
|
47
64
|
|
|
48
65
|
export function createHTTPServer<TRouter extends AnyRouter>(
|
|
49
66
|
opts: CreateHTTPHandlerOptions<TRouter>,
|
|
50
67
|
) {
|
|
51
|
-
|
|
52
|
-
return http.createServer(handler);
|
|
68
|
+
return http.createServer(createHTTPHandler(opts));
|
|
53
69
|
}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
+
import { TRPCError } from '../error/TRPCError';
|
|
2
|
+
|
|
1
3
|
export function toURL(urlOrPathname: string): URL {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
try {
|
|
5
|
+
const url = urlOrPathname.startsWith('/')
|
|
6
|
+
? `http://127.0.0.1${urlOrPathname}`
|
|
7
|
+
: urlOrPathname;
|
|
5
8
|
|
|
6
|
-
|
|
9
|
+
return new URL(url);
|
|
10
|
+
} catch (cause) {
|
|
11
|
+
throw new TRPCError({
|
|
12
|
+
code: 'BAD_REQUEST',
|
|
13
|
+
message: 'Invalid URL',
|
|
14
|
+
cause,
|
|
15
|
+
});
|
|
16
|
+
}
|
|
7
17
|
}
|