trpc-uwebsockets 0.9.3 → 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,93 +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
- resolve() {
31
- throw new TRPCError({
32
- code: 'BAD_REQUEST',
33
- message: 'error as expected',
34
- });
35
- },
36
- })
37
- .mutation('test', {
38
- input: z.object({
39
- value: z.string(),
40
32
  }),
41
- 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 }) => {
42
46
  return {
43
47
  originalValue: input.value,
44
48
  user: ctx.user,
45
49
  };
46
- },
47
- })
48
- .query('cookie-monster', {
49
- resolve({ input, ctx }) {
50
- const cookies = ctx.req.getCookies();
51
-
52
- const combined = cookies['cookie1'] + cookies['cookie2'];
53
- ctx.res.setCookie('one', 'nom');
54
- ctx.res.setCookie('two', 'nom nom');
55
- ctx.res.setHeader('x-spooked', 'true');
56
- ctx.res.setStatus(201);
57
- return {
58
- combined,
59
- user: ctx.user,
60
- };
61
- },
62
- });
63
-
50
+ }),
51
+ manualRes: t.procedure.query(({ ctx }) => {
52
+ ctx.res.setStatus(400);
53
+ ctx.res.setHeader('manual', 'header');
54
+ return 'status 400';
55
+ }),
56
+ });
64
57
  return router;
65
58
  }
66
59
  export type Router = ReturnType<typeof makeRouter>;
67
60
 
68
61
  function makeContext() {
69
- const createContext = ({
70
- req,
71
- res,
72
- uWs,
73
- }: UWebSocketsCreateContextOptions) => {
62
+ const createContext = ({ req, res }: CreateContextOptions) => {
74
63
  const getUser = () => {
75
64
  if (req.headers.authorization === 'meow') {
76
65
  return {
77
66
  name: 'KATT',
78
67
  };
79
68
  }
80
- if (req.getCookies()?.user === 'romanzy')
81
- return {
82
- name: 'romanzy',
83
- };
84
69
  return null;
85
70
  };
86
-
87
71
  return {
88
72
  req,
89
73
  res,
90
- uWs,
74
+ // uWs,
91
75
  user: getUser(),
92
76
  };
93
77
  };
@@ -95,46 +79,25 @@ function makeContext() {
95
79
  return createContext;
96
80
  }
97
81
  export type Context = inferAsyncReturnType<ReturnType<typeof makeContext>>;
82
+
83
+ // export type Context = inferAsyncReturnType<ReturnType<typeof makeContext>>;
98
84
  async function startServer() {
99
85
  const app = uWs.App();
100
86
 
101
- // Handle CORS
102
- app.options('/trpc/*', (res) => {
103
- res.writeHeader('Access-Control-Allow-Origin', '*');
104
- res.writeStatus('200 OK');
105
- res.end();
106
- });
107
-
108
- app.get('/', (res) => {
109
- res.writeStatus('200 OK');
110
-
111
- res.end();
112
- });
113
-
114
- // need to register everything on the app object,
115
- // as uWebSockets does not have middleware
116
87
  createUWebSocketsHandler(app, '/trpc', {
117
- onRequest: (req, res) => {
118
- // allows for prerequest handling
119
- const origin = req.headers.origin ?? '*';
120
- res.setHeader('Access-Control-Allow-Origin', origin);
88
+ responseMeta({ ctx, paths, type, errors }) {
89
+ return {
90
+ headers: {
91
+ hello: 'world',
92
+ },
93
+ };
121
94
  },
122
95
  router: makeRouter(),
123
96
  createContext: makeContext(),
124
97
  });
125
98
 
126
- app.put('/trpc/put', (res) => {
127
- res.writeStatus('204');
128
- res.end();
129
- });
130
-
131
- app.any('/*', (res) => {
132
- res.writeStatus('404 NOT FOUND');
133
- res.end();
134
- });
135
-
136
- const { socket } = await new Promise<{
137
- socket: uWs.us_listen_socket;
99
+ let { socket } = await new Promise<{
100
+ socket: uWs.us_listen_socket | any;
138
101
  }>((resolve) => {
139
102
  app.listen('0.0.0.0', testPort, (socket) => {
140
103
  resolve({
@@ -148,6 +111,7 @@ async function startServer() {
148
111
  new Promise<void>((resolve, reject) => {
149
112
  try {
150
113
  uWs.us_listen_socket_close(socket);
114
+ socket = null;
151
115
  resolve();
152
116
  } catch (error) {
153
117
  reject();
@@ -157,16 +121,28 @@ async function startServer() {
157
121
  }
158
122
 
159
123
  function makeClient(headers) {
160
- return createTRPCClient<Router>({
161
- url: `http://localhost:${testPort}/trpc`,
162
-
163
- AbortController: AbortController as any,
164
- fetch: fetch as any,
165
- 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
+ ],
166
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
+ // });
167
143
  }
168
144
 
169
- let t!: trpc.inferAsyncReturnType<typeof startServer>;
145
+ let t!: Awaited<ReturnType<typeof startServer>>;
170
146
  beforeEach(async () => {
171
147
  t = await startServer();
172
148
  });
@@ -174,12 +150,13 @@ afterEach(async () => {
174
150
  await t.close();
175
151
  });
176
152
 
177
- test('simple query', async () => {
153
+ test('query simple success and error handling', async () => {
178
154
  // t.client.runtime.headers = ()
179
155
  const client = makeClient({});
180
156
 
157
+ // client.
181
158
  expect(
182
- await client.query('hello', {
159
+ await client.hello.query({
183
160
  who: 'test',
184
161
  })
185
162
  ).toMatchInlineSnapshot(`
@@ -188,16 +165,16 @@ test('simple query', async () => {
188
165
  }
189
166
  `);
190
167
 
191
- expect(client.query('error', null)).rejects.toThrowError('error as expected');
168
+ await expect(client.error.query()).rejects.toThrowError('error as expected');
192
169
  });
193
170
 
194
- test('mutation with header', async () => {
171
+ test('mutation and reading headers', async () => {
195
172
  const client = makeClient({
196
173
  authorization: 'meow',
197
174
  });
198
175
 
199
176
  expect(
200
- await client.mutation('test', {
177
+ await client.test.mutate({
201
178
  value: 'lala',
202
179
  })
203
180
  ).toMatchInlineSnapshot(`
@@ -210,54 +187,38 @@ test('mutation with header', async () => {
210
187
  `);
211
188
  });
212
189
 
213
- // Error status codes are correct
214
- test('reads cookies', async () => {
215
- const client = makeClient({
216
- cookie: 'cookie1=abc; cookie2=d.e; user=romanzy',
217
- });
218
-
219
- expect(await client.query('cookie-monster')).toMatchInlineSnapshot(`
220
- Object {
221
- "combined": "abcd.e",
222
- "user": Object {
223
- "name": "romanzy",
224
- },
225
- }
226
- `);
227
- });
228
-
229
- test('setting cookies and headers', async () => {
230
- const monsterRes = await fetch(
231
- `http://localhost:${testPort}/trpc/cookie-monster`
232
- );
233
- expect(monsterRes.status).toEqual(201);
234
- expect(monsterRes.headers.get('set-cookie')).toEqual(
235
- '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('{}')}`
236
193
  );
237
- 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
238
199
  });
239
200
 
240
- test('error handling', async () => {
241
- const indexRes = await fetch(`http://localhost:${testPort}`);
242
- expect(indexRes.status).toEqual(200);
243
-
244
- const putRes = await fetch(`http://localhost:${testPort}/trpc/put`, {
245
- method: 'PUT',
246
- });
247
- expect(putRes.status).toEqual(204);
248
-
249
- const badInput = '{"who": "test';
250
- const badRes = await fetch(
251
- `http://localhost:${testPort}/trpc/hello?input=${badInput}`
252
- );
253
- expect(badRes.status).toEqual(400);
254
-
255
- const badPath = await fetch(
256
- `http://localhost:${testPort}/trpc/nonexisting?input=${badInput}`
257
- );
258
- expect(badPath.status).toEqual(400);
259
-
260
- const uncaught = await fetch(`http://localhost:${testPort}/badurl`);
261
-
262
- expect(uncaught.status).toEqual(404);
263
- });
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;