trpc-uwebsockets 0.9.4 → 0.10.0-proxy-beta.8

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.
@@ -1,103 +1,77 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import AbortController from 'abort-controller';
3
2
  import fetch from 'node-fetch';
4
- import { UWebSocketsCreateContextOptions } from '../src/types';
3
+ import { CreateContextOptions } from '../src/types';
5
4
  import uWs from 'uWebSockets.js';
6
5
  import z from 'zod';
7
- import * as trpc from '@trpc/server';
8
- import { inferAsyncReturnType, TRPCError } from '@trpc/server';
9
6
  import { createUWebSocketsHandler } from '../src/index';
10
- import { createTRPCClient, HTTPHeaders } from '@trpc/client';
7
+ import {
8
+ createTRPCProxyClient,
9
+ httpBatchLink,
10
+ TRPCClientError,
11
+ } from '@trpc/client';
12
+ import { inferAsyncReturnType, initTRPC, TRPCError } from '@trpc/server';
11
13
 
12
14
  const testPort = 8799;
13
15
 
14
16
  function makeRouter() {
15
- const router = trpc
16
- .router<Context>()
17
- .query('hello', {
18
- input: z
19
- .object({
20
- who: z.string().nullish(),
21
- })
22
- .nullish(),
23
- resolve({ input, ctx }) {
17
+ const t = initTRPC.context<Context>().create();
18
+
19
+ const router = t.router({
20
+ hello: t.procedure
21
+ .input(
22
+ z
23
+ .object({
24
+ who: z.string().nullish(),
25
+ })
26
+ .nullish()
27
+ )
28
+ .query(({ input, ctx }) => {
24
29
  return {
25
30
  text: `hello ${input?.who ?? ctx.user?.name ?? 'world'}`,
26
31
  };
27
- },
28
- })
29
- .query('error', {
30
- async resolve() {
31
- throw new TRPCError({
32
- code: 'BAD_REQUEST',
33
- message: 'error as expected',
34
- });
35
- },
36
- })
37
- .mutation('long-payload', {
38
- input: z.object({
39
- ping: z.any(),
40
32
  }),
41
- async resolve({ input }) {
42
- return {
43
- pong: input.ping,
44
- };
45
- },
46
- })
47
- .mutation('test', {
48
- input: z.object({
49
- value: z.string(),
50
- }),
51
- resolve({ input, ctx }) {
33
+ error: t.procedure.query(() => {
34
+ throw new TRPCError({
35
+ code: 'BAD_REQUEST',
36
+ message: 'error as expected',
37
+ });
38
+ }),
39
+ test: t.procedure
40
+ .input(
41
+ z.object({
42
+ value: z.string(),
43
+ })
44
+ )
45
+ .mutation(({ input, ctx }) => {
52
46
  return {
53
47
  originalValue: input.value,
54
48
  user: ctx.user,
55
49
  };
56
- },
57
- })
58
- .query('cookie-monster', {
59
- resolve({ input, ctx }) {
60
- const cookies = ctx.req.getCookies();
61
-
62
- const combined = cookies['cookie1'] + cookies['cookie2'];
63
- ctx.res.setCookie('one', 'nom');
64
- ctx.res.setCookie('two', 'nom nom');
65
- ctx.res.setHeader('x-spooked', 'true');
66
- ctx.res.setStatus(201);
67
- return {
68
- combined,
69
- user: ctx.user,
70
- };
71
- },
72
- });
73
-
50
+ }),
51
+ manualRes: t.procedure.query(({ ctx }) => {
52
+ ctx.res.setStatus(400);
53
+ ctx.res.setHeader('manual', 'header');
54
+ return 'status 400';
55
+ }),
56
+ });
74
57
  return router;
75
58
  }
76
59
  export type Router = ReturnType<typeof makeRouter>;
77
60
 
78
61
  function makeContext() {
79
- const createContext = ({
80
- req,
81
- res,
82
- uWs,
83
- }: UWebSocketsCreateContextOptions) => {
62
+ const createContext = ({ req, res }: CreateContextOptions) => {
84
63
  const getUser = () => {
85
64
  if (req.headers.authorization === 'meow') {
86
65
  return {
87
66
  name: 'KATT',
88
67
  };
89
68
  }
90
- if (req.getCookies()?.user === 'romanzy')
91
- return {
92
- name: 'romanzy',
93
- };
94
69
  return null;
95
70
  };
96
-
97
71
  return {
98
72
  req,
99
73
  res,
100
- uWs,
74
+ // uWs,
101
75
  user: getUser(),
102
76
  };
103
77
  };
@@ -105,46 +79,25 @@ function makeContext() {
105
79
  return createContext;
106
80
  }
107
81
  export type Context = inferAsyncReturnType<ReturnType<typeof makeContext>>;
82
+
83
+ // export type Context = inferAsyncReturnType<ReturnType<typeof makeContext>>;
108
84
  async function startServer() {
109
85
  const app = uWs.App();
110
86
 
111
- // Handle CORS
112
- app.options('/trpc/*', (res) => {
113
- res.writeHeader('Access-Control-Allow-Origin', '*');
114
- res.writeStatus('200 OK');
115
- res.end();
116
- });
117
-
118
- app.get('/', (res) => {
119
- res.writeStatus('200 OK');
120
-
121
- res.end();
122
- });
123
-
124
- // need to register everything on the app object,
125
- // as uWebSockets does not have middleware
126
87
  createUWebSocketsHandler(app, '/trpc', {
127
- // onRequest: (req, res) => {
128
- // // allows for prerequest handling
129
- // const origin = req.headers.origin ?? '*';
130
- // res.setHeader('Access-Control-Allow-Origin', origin);
131
- // },
88
+ responseMeta({ ctx, paths, type, errors }) {
89
+ return {
90
+ headers: {
91
+ hello: 'world',
92
+ },
93
+ };
94
+ },
132
95
  router: makeRouter(),
133
96
  createContext: makeContext(),
134
97
  });
135
98
 
136
- app.put('/trpc/put', (res) => {
137
- res.writeStatus('204');
138
- res.end();
139
- });
140
-
141
- app.any('/*', (res) => {
142
- res.writeStatus('404 NOT FOUND');
143
- res.end();
144
- });
145
-
146
- const { socket } = await new Promise<{
147
- socket: uWs.us_listen_socket;
99
+ let { socket } = await new Promise<{
100
+ socket: uWs.us_listen_socket | any;
148
101
  }>((resolve) => {
149
102
  app.listen('0.0.0.0', testPort, (socket) => {
150
103
  resolve({
@@ -158,6 +111,7 @@ async function startServer() {
158
111
  new Promise<void>((resolve, reject) => {
159
112
  try {
160
113
  uWs.us_listen_socket_close(socket);
114
+ socket = null;
161
115
  resolve();
162
116
  } catch (error) {
163
117
  reject();
@@ -167,16 +121,28 @@ async function startServer() {
167
121
  }
168
122
 
169
123
  function makeClient(headers) {
170
- return createTRPCClient<Router>({
171
- url: `http://localhost:${testPort}/trpc`,
172
-
173
- AbortController: AbortController as any,
174
- fetch: fetch as any,
175
- headers,
124
+ const client = createTRPCProxyClient<Router>({
125
+ links: [
126
+ httpBatchLink({
127
+ url: `http://localhost:${testPort}/trpc`,
128
+ fetch: fetch as any,
129
+ headers,
130
+ }),
131
+ ],
176
132
  });
133
+ return client;
134
+ // client.
135
+
136
+ // return createTRPCClient<Router>({
137
+ // url: `http://localhost:${testPort}/trpc`,
138
+
139
+ // AbortController: AbortController as any,
140
+ // fetch: fetch as any,
141
+ // headers,
142
+ // });
177
143
  }
178
144
 
179
- let t!: trpc.inferAsyncReturnType<typeof startServer>;
145
+ let t!: Awaited<ReturnType<typeof startServer>>;
180
146
  beforeEach(async () => {
181
147
  t = await startServer();
182
148
  });
@@ -184,12 +150,13 @@ afterEach(async () => {
184
150
  await t.close();
185
151
  });
186
152
 
187
- test('simple query', async () => {
153
+ test('query simple success and error handling', async () => {
188
154
  // t.client.runtime.headers = ()
189
155
  const client = makeClient({});
190
156
 
157
+ // client.
191
158
  expect(
192
- await client.query('hello', {
159
+ await client.hello.query({
193
160
  who: 'test',
194
161
  })
195
162
  ).toMatchInlineSnapshot(`
@@ -198,16 +165,16 @@ test('simple query', async () => {
198
165
  }
199
166
  `);
200
167
 
201
- expect(client.query('error', null)).rejects.toThrowError('error as expected');
168
+ await expect(client.error.query()).rejects.toThrowError('error as expected');
202
169
  });
203
170
 
204
- test('mutation with header', async () => {
171
+ test('mutation and reading headers', async () => {
205
172
  const client = makeClient({
206
173
  authorization: 'meow',
207
174
  });
208
175
 
209
176
  expect(
210
- await client.mutation('test', {
177
+ await client.test.mutate({
211
178
  value: 'lala',
212
179
  })
213
180
  ).toMatchInlineSnapshot(`
@@ -220,67 +187,38 @@ test('mutation with header', async () => {
220
187
  `);
221
188
  });
222
189
 
223
- // Error status codes are correct
224
- test('reads cookies', async () => {
225
- const client = makeClient({
226
- cookie: 'cookie1=abc; cookie2=d.e; user=romanzy',
227
- });
228
-
229
- expect(await client.query('cookie-monster')).toMatchInlineSnapshot(`
230
- Object {
231
- "combined": "abcd.e",
232
- "user": Object {
233
- "name": "romanzy",
234
- },
235
- }
236
- `);
237
- });
238
-
239
- test('setting cookies and headers', async () => {
240
- const monsterRes = await fetch(
241
- `http://localhost:${testPort}/trpc/cookie-monster`
242
- );
243
- expect(monsterRes.status).toEqual(201);
244
- expect(monsterRes.headers.get('set-cookie')).toEqual(
245
- 'one=nom, two=nom%20nom'
190
+ test('manually sets status and headers', async () => {
191
+ const fetcher = await fetch(
192
+ `http://localhost:${testPort}/trpc/manualRes?input=${encodeURI('{}')}`
246
193
  );
247
- expect(monsterRes.headers.get('x-spooked')).toEqual('true');
194
+ const body = await fetcher.json();
195
+ expect(fetcher.status).toEqual(400);
196
+ expect(body.result.data).toEqual('status 400');
197
+ expect(fetcher.headers.get('hello')).toEqual('world'); // from the meta
198
+ expect(fetcher.headers.get('manual')).toEqual('header'); //from the result
248
199
  });
249
200
 
250
- test('long payload', async () => {
251
- const client = makeClient({});
252
- const data = [...Array(50000)].map((x) => 0);
253
-
254
- expect(
255
- await client.mutation('long-payload', {
256
- ping: data,
257
- })
258
- ).toEqual({
259
- pong: data,
260
- });
261
- });
262
-
263
- test('error handling', async () => {
264
- const indexRes = await fetch(`http://localhost:${testPort}`);
265
- expect(indexRes.status).toEqual(200);
266
-
267
- const putRes = await fetch(`http://localhost:${testPort}/trpc/put`, {
268
- method: 'PUT',
269
- });
270
- expect(putRes.status).toEqual(204);
271
-
272
- const badInput = '{"who": "test';
273
- const badRes = await fetch(
274
- `http://localhost:${testPort}/trpc/hello?input=${badInput}`
275
- );
276
- expect(badRes.status).toEqual(400);
277
-
278
- const badPath = await fetch(
279
- `http://localhost:${testPort}/trpc/nonexisting?input=${badInput}`
280
- );
281
- expect(badPath.status).toEqual(400);
282
-
283
- const uncaught = await fetch(`http://localhost:${testPort}/badurl`);
284
-
285
- expect(uncaught.status).toEqual(404);
286
- });
201
+ // this needs to be tested
202
+ // test('abort works okay', async () => {
203
+ // const ac = new AbortController();
204
+ // const client = makeClient({});
205
+
206
+ // setTimeout(() => {
207
+ // ac.abort();
208
+ // }, 3);
209
+ // const res = await client.test.mutate(
210
+ // {
211
+ // value: 'haha',
212
+ // },
213
+ // {
214
+ // signal: ac.signal as any,
215
+ // }
216
+ // );
217
+
218
+ // expect(res).toMatchInlineSnapshot(`
219
+ // Object {
220
+ // "originalValue": "haha",
221
+ // "user": null,
222
+ // }
223
+ // `);
224
+ // });
package/types/index.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import { AnyRouter } from '@trpc/server';
2
2
  import type { TemplatedApp } from 'uWebSockets.js';
3
- import { UWebSocketsCreateHandlerOptions } from './types';
4
- export * from './types';
3
+ import { uHTTPHandlerOptions } from './types';
5
4
  /**
6
5
  * @param uWsApp uWebsockets server instance
7
- * @param pathPrefix The path to trpc without trailing slash (ex: "/trpc")
6
+ * @param prefix The path to trpc without trailing slash (ex: "/trpc")
8
7
  * @param opts handler options
9
8
  */
10
- export declare function createUWebSocketsHandler<TRouter extends AnyRouter>(uWsApp: TemplatedApp, pathPrefix: string, opts: UWebSocketsCreateHandlerOptions<TRouter>): void;
9
+ export declare function createUWebSocketsHandler<TRouter extends AnyRouter>(uWsApp: TemplatedApp, prefix: string, opts: uHTTPHandlerOptions<TRouter>): void;
@@ -0,0 +1,3 @@
1
+ import { AnyRouter } from '@trpc/server';
2
+ import { uHTTPRequestHandlerOptions } from './types';
3
+ export declare function uWsHTTPRequestHandler<TRouter extends AnyRouter>(opts: uHTTPRequestHandlerOptions<TRouter>): Promise<void>;
package/types/types.d.ts CHANGED
@@ -1,25 +1,23 @@
1
- import { AnyRouter, inferRouterContext } from '@trpc/server';
2
- import { TemplatedApp } from 'uWebSockets.js';
3
- import { CookieParseOptions, CookieSerializeOptions } from 'cookie';
4
- export declare type UWebSocketsCreateHandlerOptions<TRouter extends AnyRouter> = {
5
- router: TRouter;
6
- createContext?: (opts: UWebSocketsCreateContextOptions) => Promise<inferRouterContext<TRouter>> | inferRouterContext<TRouter>;
7
- onRequest?: (req: UWebSocketsRequestObject, res: UWebSocketsResponseObject) => void;
8
- };
9
- export declare type UWebSocketsRequestObject = {
1
+ import { HttpResponse } from 'uWebSockets.js';
2
+ import { AnyRouter } from '@trpc/server';
3
+ import { NodeHTTPCreateContextFnOptions, NodeHTTPCreateContextOption } from '@trpc/server/adapters/node-http';
4
+ import { HTTPBaseHandlerOptions } from '@trpc/server/dist/http/internals/types';
5
+ export declare type WrappedHTTPRequest = {
10
6
  headers: Record<string, string>;
11
7
  method: 'POST' | 'GET';
12
- query: URLSearchParams;
13
- path: string;
14
- getCookies: (opts?: CookieParseOptions) => Record<string, string>;
8
+ query: string;
9
+ url: string;
15
10
  };
16
- export declare type UWebSocketsResponseObject = {
17
- setCookie(key: string, value: string, opts?: CookieSerializeOptions): void;
11
+ export declare type WrappedHTTPResponse = {
18
12
  setStatus(status: number): void;
19
13
  setHeader(key: string, value: string): void;
20
14
  };
21
- export declare type UWebSocketsCreateContextOptions = {
22
- req: UWebSocketsRequestObject;
23
- uWs: TemplatedApp;
24
- res: UWebSocketsResponseObject;
25
- };
15
+ export declare type uHTTPHandlerOptions<TRouter extends AnyRouter> = HTTPBaseHandlerOptions<TRouter, WrappedHTTPRequest> & {
16
+ maxBodySize?: number;
17
+ } & NodeHTTPCreateContextOption<TRouter, WrappedHTTPRequest, WrappedHTTPResponse>;
18
+ export declare type uHTTPRequestHandlerOptions<TRouter extends AnyRouter> = {
19
+ req: WrappedHTTPRequest;
20
+ uRes: HttpResponse;
21
+ path: string;
22
+ } & uHTTPHandlerOptions<TRouter>;
23
+ export declare type CreateContextOptions = NodeHTTPCreateContextFnOptions<WrappedHTTPRequest, WrappedHTTPResponse>;
package/types/utils.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { TRPCError } from '@trpc/server';
2
1
  import { HttpResponse } from 'uWebSockets.js';
3
- import { CookieParseOptions } from 'cookie';
4
- export declare const getCookieFn: (headers: Record<string, string>) => (opts?: CookieParseOptions) => Record<string, string>;
5
- export declare function readPostBody(method: string, res: HttpResponse): Promise<{
2
+ import { WrappedHTTPRequest, WrappedHTTPResponse } from './types';
3
+ import { AnyRouter, TRPCError } from '@trpc/server';
4
+ export declare function getPostBody<TRouter extends AnyRouter, TRequest extends WrappedHTTPRequest, TResponse extends WrappedHTTPResponse>(method: any, res: HttpResponse, maxBodySize?: number): Promise<{
6
5
  ok: true;
7
6
  data: unknown;
8
7
  } | {
9
8
  ok: false;
10
9
  error: TRPCError;
11
10
  }>;
11
+ export declare function sendResponse(res: HttpResponse, payload?: string): void;