@dokploy/trpc-openapi 0.0.1

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 (126) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +369 -0
  3. package/assets/trpc-openapi-graph.png +0 -0
  4. package/assets/trpc-openapi-readme.png +0 -0
  5. package/assets/trpc-openapi.svg +4 -0
  6. package/dist/adapters/express.d.ts +6 -0
  7. package/dist/adapters/express.d.ts.map +1 -0
  8. package/dist/adapters/express.js +12 -0
  9. package/dist/adapters/express.js.map +1 -0
  10. package/dist/adapters/index.d.ts +4 -0
  11. package/dist/adapters/index.d.ts.map +1 -0
  12. package/dist/adapters/index.js +20 -0
  13. package/dist/adapters/index.js.map +1 -0
  14. package/dist/adapters/next.d.ts +6 -0
  15. package/dist/adapters/next.d.ts.map +1 -0
  16. package/dist/adapters/next.js +45 -0
  17. package/dist/adapters/next.js.map +1 -0
  18. package/dist/adapters/node-http/core.d.ts +6 -0
  19. package/dist/adapters/node-http/core.d.ts.map +1 -0
  20. package/dist/adapters/node-http/core.js +140 -0
  21. package/dist/adapters/node-http/core.js.map +1 -0
  22. package/dist/adapters/node-http/errors.d.ts +4 -0
  23. package/dist/adapters/node-http/errors.d.ts.map +1 -0
  24. package/dist/adapters/node-http/errors.js +43 -0
  25. package/dist/adapters/node-http/errors.js.map +1 -0
  26. package/dist/adapters/node-http/input.d.ts +4 -0
  27. package/dist/adapters/node-http/input.d.ts.map +1 -0
  28. package/dist/adapters/node-http/input.js +76 -0
  29. package/dist/adapters/node-http/input.js.map +1 -0
  30. package/dist/adapters/node-http/procedures.d.ts +12 -0
  31. package/dist/adapters/node-http/procedures.d.ts.map +1 -0
  32. package/dist/adapters/node-http/procedures.js +51 -0
  33. package/dist/adapters/node-http/procedures.js.map +1 -0
  34. package/dist/adapters/standalone.d.ts +6 -0
  35. package/dist/adapters/standalone.d.ts.map +1 -0
  36. package/dist/adapters/standalone.js +12 -0
  37. package/dist/adapters/standalone.js.map +1 -0
  38. package/dist/generator/index.d.ts +14 -0
  39. package/dist/generator/index.d.ts.map +1 -0
  40. package/dist/generator/index.js +39 -0
  41. package/dist/generator/index.js.map +1 -0
  42. package/dist/generator/paths.d.ts +4 -0
  43. package/dist/generator/paths.d.ts.map +1 -0
  44. package/dist/generator/paths.js +76 -0
  45. package/dist/generator/paths.js.map +1 -0
  46. package/dist/generator/schema.d.ts +7 -0
  47. package/dist/generator/schema.d.ts.map +1 -0
  48. package/dist/generator/schema.js +195 -0
  49. package/dist/generator/schema.js.map +1 -0
  50. package/dist/index.d.ts +6 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +11 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/types.d.ts +53 -0
  55. package/dist/types.d.ts.map +1 -0
  56. package/dist/types.js +3 -0
  57. package/dist/types.js.map +1 -0
  58. package/dist/utils/method.d.ts +3 -0
  59. package/dist/utils/method.d.ts.map +1 -0
  60. package/dist/utils/method.js +11 -0
  61. package/dist/utils/method.js.map +1 -0
  62. package/dist/utils/path.d.ts +4 -0
  63. package/dist/utils/path.d.ts.map +1 -0
  64. package/dist/utils/path.js +17 -0
  65. package/dist/utils/path.js.map +1 -0
  66. package/dist/utils/procedure.d.ts +14 -0
  67. package/dist/utils/procedure.d.ts.map +1 -0
  68. package/dist/utils/procedure.js +39 -0
  69. package/dist/utils/procedure.js.map +1 -0
  70. package/dist/utils/zod.d.ts +19 -0
  71. package/dist/utils/zod.d.ts.map +1 -0
  72. package/dist/utils/zod.js +87 -0
  73. package/dist/utils/zod.js.map +1 -0
  74. package/examples/with-express/README.md +11 -0
  75. package/examples/with-express/package.json +28 -0
  76. package/examples/with-express/src/database.ts +67 -0
  77. package/examples/with-express/src/index.ts +27 -0
  78. package/examples/with-express/src/openapi.ts +13 -0
  79. package/examples/with-express/src/router.ts +424 -0
  80. package/examples/with-express/tsconfig.json +102 -0
  81. package/examples/with-interop/README.md +10 -0
  82. package/examples/with-interop/package.json +13 -0
  83. package/examples/with-interop/src/index.ts +17 -0
  84. package/examples/with-interop/tsconfig.json +103 -0
  85. package/examples/with-nextjs/.eslintrc.json +3 -0
  86. package/examples/with-nextjs/README.md +12 -0
  87. package/examples/with-nextjs/next-env.d.ts +5 -0
  88. package/examples/with-nextjs/next.config.js +6 -0
  89. package/examples/with-nextjs/package.json +33 -0
  90. package/examples/with-nextjs/public/favicon.ico +0 -0
  91. package/examples/with-nextjs/src/pages/_app.tsx +7 -0
  92. package/examples/with-nextjs/src/pages/api/[...trpc].ts +18 -0
  93. package/examples/with-nextjs/src/pages/api/openapi.json.ts +10 -0
  94. package/examples/with-nextjs/src/pages/api/trpc/[...trpc].ts +9 -0
  95. package/examples/with-nextjs/src/pages/index.tsx +12 -0
  96. package/examples/with-nextjs/src/server/database.ts +67 -0
  97. package/examples/with-nextjs/src/server/openapi.ts +13 -0
  98. package/examples/with-nextjs/src/server/router.ts +426 -0
  99. package/examples/with-nextjs/tsconfig.json +24 -0
  100. package/jest.config.ts +12 -0
  101. package/package.json +74 -0
  102. package/pnpm-workspace.yaml +7 -0
  103. package/src/adapters/express.ts +20 -0
  104. package/src/adapters/index.ts +3 -0
  105. package/src/adapters/next.ts +64 -0
  106. package/src/adapters/node-http/core.ts +203 -0
  107. package/src/adapters/node-http/errors.ts +45 -0
  108. package/src/adapters/node-http/input.ts +76 -0
  109. package/src/adapters/node-http/procedures.ts +64 -0
  110. package/src/adapters/standalone.ts +19 -0
  111. package/src/generator/index.ts +51 -0
  112. package/src/generator/paths.ts +127 -0
  113. package/src/generator/schema.ts +238 -0
  114. package/src/index.ts +42 -0
  115. package/src/types.ts +79 -0
  116. package/src/utils/method.ts +8 -0
  117. package/src/utils/path.ts +12 -0
  118. package/src/utils/procedure.ts +45 -0
  119. package/src/utils/zod.ts +115 -0
  120. package/test/adapters/express.test.ts +150 -0
  121. package/test/adapters/next.test.ts +162 -0
  122. package/test/adapters/standalone.test.ts +1335 -0
  123. package/test/generator.test.ts +2897 -0
  124. package/tsconfig.build.json +4 -0
  125. package/tsconfig.eslint.json +5 -0
  126. package/tsconfig.json +19 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 James Berry <jb@jamesbe.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,369 @@
1
+ ![trpc-openapi](assets/trpc-openapi-readme.png)
2
+
3
+ <div align="center">
4
+ <h1>trpc-openapi</h1>
5
+ <a href="https://www.npmjs.com/package/trpc-openapi"><img src="https://img.shields.io/npm/v/trpc-openapi.svg?style=flat&color=brightgreen" target="_blank" /></a>
6
+ <a href="./LICENSE"><img src="https://img.shields.io/badge/license-MIT-black" /></a>
7
+ <a href="https://trpc.io/discord" target="_blank"><img src="https://img.shields.io/badge/chat-discord-blue.svg" /></a>
8
+ <br />
9
+ <hr />
10
+ </div>
11
+
12
+ #### `trpc-openapi` is maintained by ProsePilot - simple, fast and free online [writing tools](https://www.prosepilot.com/tools).
13
+
14
+ ---
15
+
16
+ ## **[OpenAPI](https://swagger.io/specification/) support for [tRPC](https://trpc.io/)** 🧩
17
+
18
+ - Easy REST endpoints for your tRPC procedures.
19
+ - Perfect for incremental adoption.
20
+ - OpenAPI version 3.0.3.
21
+
22
+ ## Usage
23
+
24
+ **1. Install `trpc-openapi`.**
25
+
26
+ ```bash
27
+ # npm
28
+ npm install trpc-openapi
29
+ # yarn
30
+ yarn add trpc-openapi
31
+ ```
32
+
33
+ **2. Add `OpenApiMeta` to your tRPC instance.**
34
+
35
+ ```typescript
36
+ import { initTRPC } from '@trpc/server';
37
+ import { OpenApiMeta } from 'trpc-openapi';
38
+
39
+ const t = initTRPC.meta<OpenApiMeta>().create(); /* 👈 */
40
+ ```
41
+
42
+ **3. Enable `openapi` support for a procedure.**
43
+
44
+ ```typescript
45
+ export const appRouter = t.router({
46
+ sayHello: t.procedure
47
+ .meta({ /* 👉 */ openapi: { method: 'GET', path: '/say-hello' } })
48
+ .input(z.object({ name: z.string() }))
49
+ .output(z.object({ greeting: z.string() }))
50
+ .query(({ input }) => {
51
+ return { greeting: `Hello ${input.name}!` };
52
+ });
53
+ });
54
+ ```
55
+
56
+ **4. Generate an OpenAPI document.**
57
+
58
+ ```typescript
59
+ import { generateOpenApiDocument } from 'trpc-openapi';
60
+
61
+ import { appRouter } from '../appRouter';
62
+
63
+ /* 👇 */
64
+ export const openApiDocument = generateOpenApiDocument(appRouter, {
65
+ title: 'tRPC OpenAPI',
66
+ version: '1.0.0',
67
+ baseUrl: 'http://localhost:3000',
68
+ });
69
+ ```
70
+
71
+ **5. Add an `trpc-openapi` handler to your app.**
72
+
73
+ We currently support adapters for [`Express`](http://expressjs.com/), [`Next.js`](https://nextjs.org/), [`Serverless`](https://www.serverless.com/), [`Fastify`](https://www.fastify.io/), [`Nuxt`](https://nuxtjs.org/) & [`Node:HTTP`](https://nodejs.org/api/http.html).
74
+
75
+ [`Fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API), [`Cloudflare Workers`](https://workers.cloudflare.com/) & more soon™, PRs are welcomed 🙌.
76
+
77
+ ```typescript
78
+ import http from 'http';
79
+ import { createOpenApiHttpHandler } from 'trpc-openapi';
80
+
81
+ import { appRouter } from '../appRouter';
82
+
83
+ const server = http.createServer(createOpenApiHttpHandler({ router: appRouter })); /* 👈 */
84
+
85
+ server.listen(3000);
86
+ ```
87
+
88
+ **6. Profit 🤑**
89
+
90
+ ```typescript
91
+ // client.ts
92
+ const res = await fetch('http://localhost:3000/say-hello?name=James', { method: 'GET' });
93
+ const body = await res.json(); /* { greeting: 'Hello James!' } */
94
+ ```
95
+
96
+ ## Requirements
97
+
98
+ Peer dependencies:
99
+
100
+ - [`tRPC`](https://github.com/trpc/trpc) Server v10 (`@trpc/server`) must be installed.
101
+ - [`Zod`](https://github.com/colinhacks/zod) v3 (`zod@^3.14.4`) must be installed (recommended `^3.20.0`).
102
+
103
+ For a procedure to support OpenAPI the following _must_ be true:
104
+
105
+ - Both `input` and `output` parsers are present AND use `Zod` validation.
106
+ - Query `input` parsers extend `Object<{ [string]: String | Number | BigInt | Date }>` or `Void`.
107
+ - Mutation `input` parsers extend `Object<{ [string]: AnyType }>` or `Void`.
108
+ - `meta.openapi.method` is `GET`, `POST`, `PATCH`, `PUT` or `DELETE`.
109
+ - `meta.openapi.path` is a string starting with `/`.
110
+ - `meta.openapi.path` parameters exist in `input` parser as `String | Number | BigInt | Date`
111
+
112
+ Please note:
113
+
114
+ - Data [`transformers`](https://trpc.io/docs/data-transformers) (such as `superjson`) are ignored.
115
+ - Trailing slashes are ignored.
116
+ - Routing is case-insensitive.
117
+
118
+ ## HTTP Requests
119
+
120
+ Procedures with a `GET`/`DELETE` method will accept inputs via URL `query parameters`. Procedures with a `POST`/`PATCH`/`PUT` method will accept inputs via the `request body` with a `application/json` or `application/x-www-form-urlencoded` content type.
121
+
122
+ ### Path parameters
123
+
124
+ A procedure can accept a set of inputs via URL path parameters. You can add a path parameter to any OpenAPI procedure by using curly brackets around an input name as a path segment in the `meta.openapi.path` field.
125
+
126
+ ### Query parameters
127
+
128
+ Query & path parameter inputs are always accepted as a `string`. This library will attempt to [coerce](https://github.com/colinhacks/zod#coercion-for-primitives) your input values to the following primitive types out of the box: `number`, `boolean`, `bigint` and `date`. If you wish to support others such as `object`, `array` etc. please use [`z.preprocess()`](https://github.com/colinhacks/zod#preprocess).
129
+
130
+ ```typescript
131
+ // Router
132
+ export const appRouter = t.router({
133
+ sayHello: t.procedure
134
+ .meta({ openapi: { method: 'GET', path: '/say-hello/{name}' /* 👈 */ } })
135
+ .input(z.object({ name: z.string() /* 👈 */, greeting: z.string() }))
136
+ .output(z.object({ greeting: z.string() }))
137
+ .query(({ input }) => {
138
+ return { greeting: `${input.greeting} ${input.name}!` };
139
+ });
140
+ });
141
+
142
+ // Client
143
+ const res = await fetch('http://localhost:3000/say-hello/James?greeting=Hello' /* 👈 */, {
144
+ method: 'GET',
145
+ });
146
+ const body = await res.json(); /* { greeting: 'Hello James!' } */
147
+ ```
148
+
149
+ ### Request body
150
+
151
+ ```typescript
152
+ // Router
153
+ export const appRouter = t.router({
154
+ sayHello: t.procedure
155
+ .meta({ openapi: { method: 'POST', path: '/say-hello/{name}' /* 👈 */ } })
156
+ .input(z.object({ name: z.string() /* 👈 */, greeting: z.string() }))
157
+ .output(z.object({ greeting: z.string() }))
158
+ .mutation(({ input }) => {
159
+ return { greeting: `${input.greeting} ${input.name}!` };
160
+ });
161
+ });
162
+
163
+ // Client
164
+ const res = await fetch('http://localhost:3000/say-hello/James' /* 👈 */, {
165
+ method: 'POST',
166
+ headers: { 'Content-Type': 'application/json' },
167
+ body: JSON.stringify({ greeting: 'Hello' }),
168
+ });
169
+ const body = await res.json(); /* { greeting: 'Hello James!' } */
170
+ ```
171
+
172
+ ### Custom headers
173
+
174
+ Any custom headers can be specified in the `meta.openapi.headers` array, these headers will not be validated on request. Please consider using [Authorization](#authorization) for first-class OpenAPI auth/security support.
175
+
176
+ ## HTTP Responses
177
+
178
+ Status codes will be `200` by default for any successful requests. In the case of an error, the status code will be derived from the thrown `TRPCError` or fallback to `500`.
179
+
180
+ You can modify the status code or headers for any response using the `responseMeta` function.
181
+
182
+ Please see [error status codes here](src/adapters/node-http/errors.ts).
183
+
184
+ ## Authorization
185
+
186
+ To create protected endpoints, add `protect: true` to the `meta.openapi` object of each tRPC procedure. By default, you can then authenticate each request with the `createContext` function using the `Authorization` header with the `Bearer` scheme. If you wish to authenticate requests using a different/additional methods (such as custom headers, or cookies) this can be overwritten by specifying `securitySchemes` object.
187
+
188
+ Explore a [complete example here](examples/with-nextjs/src/server/router.ts).
189
+
190
+ #### Server
191
+
192
+ ```typescript
193
+ import { TRPCError, initTRPC } from '@trpc/server';
194
+ import { OpenApiMeta } from 'trpc-openapi';
195
+
196
+ type User = { id: string; name: string };
197
+
198
+ const users: User[] = [
199
+ {
200
+ id: 'usr_123',
201
+ name: 'James',
202
+ },
203
+ ];
204
+
205
+ export type Context = { user: User | null };
206
+
207
+ export const createContext = async ({ req, res }): Promise<Context> => {
208
+ let user: User | null = null;
209
+ if (req.headers.authorization) {
210
+ const userId = req.headers.authorization.split(' ')[1];
211
+ user = users.find((_user) => _user.id === userId);
212
+ }
213
+ return { user };
214
+ };
215
+
216
+ const t = initTRPC.context<Context>().meta<OpenApiMeta>().create();
217
+
218
+ export const appRouter = t.router({
219
+ sayHello: t.procedure
220
+ .meta({ openapi: { method: 'GET', path: '/say-hello', protect: true /* 👈 */ } })
221
+ .input(z.void()) // no input expected
222
+ .output(z.object({ greeting: z.string() }))
223
+ .query(({ input, ctx }) => {
224
+ if (!ctx.user) {
225
+ throw new TRPCError({ message: 'User not found', code: 'UNAUTHORIZED' });
226
+ }
227
+ return { greeting: `Hello ${ctx.user.name}!` };
228
+ }),
229
+ });
230
+ ```
231
+
232
+ #### Client
233
+
234
+ ```typescript
235
+ const res = await fetch('http://localhost:3000/say-hello', {
236
+ method: 'GET',
237
+ headers: { Authorization: 'Bearer usr_123' } /* 👈 */,
238
+ });
239
+ const body = await res.json(); /* { greeting: 'Hello James!' } */
240
+ ```
241
+
242
+ ## Examples
243
+
244
+ _For advanced use-cases, please find examples in our [complete test suite](test)._
245
+
246
+ #### With Express
247
+
248
+ Please see [full example here](examples/with-express).
249
+
250
+ ```typescript
251
+ import { createExpressMiddleware } from '@trpc/server/adapters/express';
252
+ import express from 'express';
253
+ import { createOpenApiExpressMiddleware } from 'trpc-openapi';
254
+
255
+ import { appRouter } from '../appRouter';
256
+
257
+ const app = express();
258
+
259
+ app.use('/api/trpc', createExpressMiddleware({ router: appRouter }));
260
+ app.use('/api', createOpenApiExpressMiddleware({ router: appRouter })); /* 👈 */
261
+
262
+ app.listen(3000);
263
+ ```
264
+
265
+ #### With Next.js
266
+
267
+ Please see [full example here](examples/with-nextjs).
268
+
269
+ ```typescript
270
+ // pages/api/[...trpc].ts
271
+ import { createOpenApiNextHandler } from 'trpc-openapi';
272
+
273
+ import { appRouter } from '../../server/appRouter';
274
+
275
+ export default createOpenApiNextHandler({ router: appRouter });
276
+ ```
277
+
278
+ #### With AWS Lambda
279
+
280
+ Please see [full example here](examples/with-serverless).
281
+
282
+ ```typescript
283
+ import { createOpenApiAwsLambdaHandler } from 'trpc-openapi';
284
+
285
+ import { appRouter } from './appRouter';
286
+
287
+ export const openApi = createOpenApiAwsLambdaHandler({ router: appRouter });
288
+ ```
289
+
290
+ #### With Fastify
291
+
292
+ Please see [full example here](examples/with-fastify).
293
+
294
+ ```typescript
295
+ import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';
296
+ import Fastify from 'fastify';
297
+ import { fastifyTRPCOpenApiPlugin } from 'trpc-openapi';
298
+
299
+ import { appRouter } from './router';
300
+
301
+ const fastify = Fastify();
302
+
303
+ async function main() {
304
+ await fastify.register(fastifyTRPCPlugin, { router: appRouter });
305
+ await fastify.register(fastifyTRPCOpenApiPlugin, { router: appRouter }); /* 👈 */
306
+
307
+ await fastify.listen({ port: 3000 });
308
+ }
309
+
310
+ main();
311
+ ```
312
+
313
+ ## Types
314
+
315
+ #### GenerateOpenApiDocumentOptions
316
+
317
+ Please see [full typings here](src/generator/index.ts).
318
+
319
+ | Property | Type | Description | Required |
320
+ | ----------------- | -------------------------------------- | ------------------------------------------------------- | -------- |
321
+ | `title` | `string` | The title of the API. | `true` |
322
+ | `description` | `string` | A short description of the API. | `false` |
323
+ | `version` | `string` | The version of the OpenAPI document. | `true` |
324
+ | `baseUrl` | `string` | The base URL of the target server. | `true` |
325
+ | `docsUrl` | `string` | A URL to any external documentation. | `false` |
326
+ | `tags` | `string[]` | A list for ordering endpoint groups. | `false` |
327
+ | `securitySchemes` | `Record<string, SecuritySchemeObject>` | Defaults to `Authorization` header with `Bearer` scheme | `false` |
328
+
329
+ #### OpenApiMeta
330
+
331
+ Please see [full typings here](src/types.ts).
332
+
333
+ | Property | Type | Description | Required | Default |
334
+ | -------------- | ------------------- | ---------------------------------------------------------------------------------------------------- | -------- | ---------------------- |
335
+ | `enabled` | `boolean` | Exposes this procedure to `trpc-openapi` adapters and on the OpenAPI document. | `false` | `true` |
336
+ | `method` | `HttpMethod` | HTTP method this endpoint is exposed on. Value can be `GET`, `POST`, `PATCH`, `PUT` or `DELETE`. | `true` | `undefined` |
337
+ | `path` | `string` | Pathname this endpoint is exposed on. Value must start with `/`, specify path parameters using `{}`. | `true` | `undefined` |
338
+ | `protect` | `boolean` | Requires this endpoint to use a security scheme. | `false` | `false` |
339
+ | `summary` | `string` | A short summary of the endpoint included in the OpenAPI document. | `false` | `undefined` |
340
+ | `description` | `string` | A verbose description of the endpoint included in the OpenAPI document. | `false` | `undefined` |
341
+ | `tags` | `string[]` | A list of tags used for logical grouping of endpoints in the OpenAPI document. | `false` | `undefined` |
342
+ | `headers` | `ParameterObject[]` | An array of custom headers to add for this endpoint in the OpenAPI document. | `false` | `undefined` |
343
+ | `contentTypes` | `ContentType[]` | A set of content types specified as accepted in the OpenAPI document. | `false` | `['application/json']` |
344
+ | `deprecated` | `boolean` | Whether or not to mark an endpoint as deprecated | `false` | `false` |
345
+
346
+ #### CreateOpenApiNodeHttpHandlerOptions
347
+
348
+ Please see [full typings here](src/adapters/node-http/core.ts).
349
+
350
+ | Property | Type | Description | Required |
351
+ | --------------- | ---------- | ------------------------------------------------------ | -------- |
352
+ | `router` | `Router` | Your application tRPC router. | `true` |
353
+ | `createContext` | `Function` | Passes contextual (`ctx`) data to procedure resolvers. | `false` |
354
+ | `responseMeta` | `Function` | Returns any modifications to statusCode & headers. | `false` |
355
+ | `onError` | `Function` | Called if error occurs inside handler. | `false` |
356
+ | `maxBodySize` | `number` | Maximum request body size in bytes (default: 100kb). | `false` |
357
+
358
+ ---
359
+
360
+ _Still using tRPC v9? See our [`.interop()`](examples/with-interop) example._
361
+
362
+ ## License
363
+
364
+ Distributed under the MIT License. See LICENSE for more information.
365
+
366
+ ## Contact
367
+
368
+ James Berry - Follow me on Twitter [@jlalmes](https://twitter.com/jlalmes) 💚
369
+ # trpc-openapi
Binary file
Binary file
@@ -0,0 +1,4 @@
1
+ <svg width="125" height="125" viewBox="0 0 125 125" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M125 62.5C125 97.0178 97.0178 125 62.5 125C27.9822 125 0 97.0178 0 62.5C0 27.9822 27.9822 0 62.5 0C97.0178 0 125 27.9822 125 62.5ZM62 17.2672L80.7143 27.764V35.3077L99 44.5385V61.5685L106 65.4948V86.736L87.2857 97.2328L82.8617 94.7514L61.9649 106.791L41.6747 94.771L37.2857 97.2328L18.5714 86.736V65.4948L25 61.889V44.5385L43.2857 35.3077V27.764L62 17.2672ZM35 50.6923L43.2857 46.5096V49.0052L62 59.502L80.7143 49.0052V46.5096L89 50.6923V55.9595L87.2857 54.998L68.5714 65.4948V86.736L72.7116 89.0582L62.0351 95.2093L51.7528 89.1183L56 86.736V65.4948L37.2857 54.9979L35 56.28V50.6923ZM83.7922 68.4231L87.2857 66.4636L90.7792 68.4231L87.2857 70.3826L83.7922 68.4231ZM92.2857 79.0437L96 76.9604V80.8794L92.2857 82.9627V79.0437ZM82.2857 79.0437V82.9627L78.5714 80.8794V76.9604L82.2857 79.0437ZM46 80.8794L42.2857 82.9627V79.0437L46 76.9604V80.8794ZM40.7792 68.4231L37.2857 70.3826L33.7922 68.4231L37.2857 66.4636L40.7792 68.4231ZM28.5714 76.9604L32.2857 79.0437V82.9627L28.5714 80.8794V76.9604ZM57 45.2319L53.2857 43.1486V39.2296L57 41.3129V45.2319ZM62 32.6518L58.5065 30.6923L62 28.7328L65.4935 30.6923L62 32.6518ZM67 41.3129L70.7143 39.2296V43.1486L67 45.2319V41.3129Z" fill="#8FCE0B"/>
3
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M62 21.2802L77.2143 29.8138V37.4615L95.5 46.6923V63.6183L102.5 67.5446V84.6862L87.2857 93.2198L82.8385 90.7254L61.9895 102.737L41.7224 90.7313L37.2857 93.2198L22.0714 84.6862V67.5446L28.5 63.9388V46.6923L46.7857 37.4615V29.8138L62 21.2802ZM46.7857 40.8221L31.5 48.5385V62.2561L37.2857 59.0109L52.5 67.5446V84.6862L44.7458 89.0355L62.0105 99.2628L79.7935 89.0175L72.0714 84.6862V67.5446L87.2857 59.0109L92.5 61.9356V48.5385L77.2143 40.8221V46.9554L62 55.4891L46.7857 46.9554V40.8221ZM49.7857 33.2535L60.5 39.2631V51.208L49.7857 45.1984V33.2535ZM63.5 51.208L74.2143 45.1984V33.2535L63.5 39.2631V51.208ZM62 36.6648L72.648 30.6923L62 24.7198L51.352 30.6923L62 36.6648ZM25.0714 70.9843L35.7857 76.9939V88.9388L25.0714 82.9292V70.9843ZM38.7857 88.9388L49.5 82.9292V70.9843L38.7857 76.9939V88.9388ZM37.2857 74.3955L47.9338 68.4231L37.2857 62.4506L26.6377 68.4231L37.2857 74.3955ZM75.0714 70.9843L85.7857 76.9939V88.9388L75.0714 82.9292V70.9843ZM88.7857 88.9388L99.5 82.9292V70.9843L88.7857 76.9939V88.9388ZM87.2857 74.3955L97.9338 68.4231L87.2857 62.4506L76.6377 68.4231L87.2857 74.3955Z" fill="#4B5A30" stroke="#4B5A30" stroke-width="1.5"/>
4
+ </svg>
@@ -0,0 +1,6 @@
1
+ import { Request, Response } from 'express';
2
+ import { OpenApiRouter } from '../types';
3
+ import { CreateOpenApiNodeHttpHandlerOptions } from './node-http/core';
4
+ export type CreateOpenApiExpressMiddlewareOptions<TRouter extends OpenApiRouter> = CreateOpenApiNodeHttpHandlerOptions<TRouter, Request, Response>;
5
+ export declare const createOpenApiExpressMiddleware: <TRouter extends OpenApiRouter>(opts: CreateOpenApiExpressMiddlewareOptions<TRouter>) => (req: Request, res: Response) => Promise<void>;
6
+ //# sourceMappingURL=express.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../../src/adapters/express.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,mCAAmC,EAEpC,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,qCAAqC,CAAC,OAAO,SAAS,aAAa,IAC7E,mCAAmC,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;AAElE,eAAO,MAAM,8BAA8B,GAAI,OAAO,SAAS,aAAa,QACpE,qCAAqC,CAAC,OAAO,CAAC,WAIjC,OAAO,OAAO,QAAQ,kBAG1C,CAAC"}
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createOpenApiExpressMiddleware = void 0;
4
+ const core_1 = require("./node-http/core");
5
+ const createOpenApiExpressMiddleware = (opts) => {
6
+ const openApiHttpHandler = (0, core_1.createOpenApiNodeHttpHandler)(opts);
7
+ return async (req, res) => {
8
+ await openApiHttpHandler(req, res);
9
+ };
10
+ };
11
+ exports.createOpenApiExpressMiddleware = createOpenApiExpressMiddleware;
12
+ //# sourceMappingURL=express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.js","sourceRoot":"","sources":["../../src/adapters/express.ts"],"names":[],"mappings":";;;AAGA,2CAG0B;AAKnB,MAAM,8BAA8B,GAAG,CAC5C,IAAoD,EACpD,EAAE;IACF,MAAM,kBAAkB,GAAG,IAAA,mCAA4B,EAAC,IAAI,CAAC,CAAC;IAE9D,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;QAC3C,MAAM,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC,CAAC;AACJ,CAAC,CAAC;AARW,QAAA,8BAA8B,kCAQzC"}
@@ -0,0 +1,4 @@
1
+ export * from "./standalone";
2
+ export * from "./express";
3
+ export * from "./next";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,QAAQ,CAAC"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./standalone"), exports);
18
+ __exportStar(require("./express"), exports);
19
+ __exportStar(require("./next"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,+CAA6B;AAC7B,4CAA0B;AAC1B,yCAAuB"}
@@ -0,0 +1,6 @@
1
+ import type { NextApiRequest, NextApiResponse } from "next";
2
+ import type { OpenApiRouter } from "../types";
3
+ import { type CreateOpenApiNodeHttpHandlerOptions } from "./node-http/core";
4
+ export type CreateOpenApiNextHandlerOptions<TRouter extends OpenApiRouter> = Omit<CreateOpenApiNodeHttpHandlerOptions<TRouter, NextApiRequest, NextApiResponse>, "maxBodySize">;
5
+ export declare const createOpenApiNextHandler: <TRouter extends OpenApiRouter>(opts: CreateOpenApiNextHandlerOptions<TRouter>) => (req: NextApiRequest, res: NextApiResponse) => Promise<void>;
6
+ //# sourceMappingURL=next.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.d.ts","sourceRoot":"","sources":["../../src/adapters/next.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,MAAM,CAAC;AAE5D,OAAO,KAAK,EAAwB,aAAa,EAAE,MAAM,UAAU,CAAC;AAEpE,OAAO,EACN,KAAK,mCAAmC,EAExC,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,+BAA+B,CAAC,OAAO,SAAS,aAAa,IACxE,IAAI,CACH,mCAAmC,CAClC,OAAO,EACP,cAAc,EACd,eAAe,CACf,EACD,aAAa,CACb,CAAC;AAEH,eAAO,MAAM,wBAAwB,GAAI,OAAO,SAAS,aAAa,QAC/D,+BAA+B,CAAC,OAAO,CAAC,WAI3B,cAAc,OAAO,eAAe,kBAsCvD,CAAC"}
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createOpenApiNextHandler = void 0;
4
+ const server_1 = require("@trpc/server");
5
+ const path_1 = require("../utils/path");
6
+ const core_1 = require("./node-http/core");
7
+ const createOpenApiNextHandler = (opts) => {
8
+ const openApiHttpHandler = (0, core_1.createOpenApiNodeHttpHandler)(opts);
9
+ return async (req, res) => {
10
+ var _a;
11
+ let pathname = null;
12
+ if (typeof req.query.trpc === "string") {
13
+ pathname = req.query.trpc;
14
+ }
15
+ else if (Array.isArray(req.query.trpc)) {
16
+ pathname = req.query.trpc.join("/");
17
+ }
18
+ if (pathname === null) {
19
+ const error = new server_1.TRPCError({
20
+ message: 'Query "trpc" not found - is the `trpc-openapi` file named `[...trpc].ts`?',
21
+ code: "INTERNAL_SERVER_ERROR",
22
+ });
23
+ (_a = opts.onError) === null || _a === void 0 ? void 0 : _a.call(opts, {
24
+ error,
25
+ type: "unknown",
26
+ path: undefined,
27
+ input: undefined,
28
+ ctx: undefined,
29
+ req,
30
+ });
31
+ res.statusCode = 500;
32
+ res.setHeader("Content-Type", "application/json");
33
+ const body = {
34
+ message: error.message,
35
+ code: error.code,
36
+ };
37
+ res.end(JSON.stringify(body));
38
+ return;
39
+ }
40
+ req.url = (0, path_1.normalizePath)(pathname);
41
+ await openApiHttpHandler(req, res);
42
+ };
43
+ };
44
+ exports.createOpenApiNextHandler = createOpenApiNextHandler;
45
+ //# sourceMappingURL=next.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"next.js","sourceRoot":"","sources":["../../src/adapters/next.ts"],"names":[],"mappings":";;;AAAA,yCAAyC;AAIzC,wCAA8C;AAC9C,2CAG0B;AAYnB,MAAM,wBAAwB,GAAG,CACvC,IAA8C,EAC7C,EAAE;IACH,MAAM,kBAAkB,GAAG,IAAA,mCAA4B,EAAC,IAAI,CAAC,CAAC;IAE9D,OAAO,KAAK,EAAE,GAAmB,EAAE,GAAoB,EAAE,EAAE;;QAC1D,IAAI,QAAQ,GAAkB,IAAI,CAAC;QACnC,IAAI,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACxC,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;QAC3B,CAAC;aAAM,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1C,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,kBAAS,CAAC;gBAC3B,OAAO,EACN,2EAA2E;gBAC5E,IAAI,EAAE,uBAAuB;aAC7B,CAAC,CAAC;YAEH,MAAA,IAAI,CAAC,OAAO,qDAAG;gBACd,KAAK;gBACL,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,SAAS;gBACf,KAAK,EAAE,SAAS;gBAChB,GAAG,EAAE,SAAS;gBACd,GAAG;aACH,CAAC,CAAC;YAEH,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;YACrB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;YAClD,MAAM,IAAI,GAAyB;gBAClC,OAAO,EAAE,KAAK,CAAC,OAAO;gBACtB,IAAI,EAAE,KAAK,CAAC,IAAI;aAChB,CAAC;YACF,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;YAE9B,OAAO;QACR,CAAC;QAED,GAAG,CAAC,GAAG,GAAG,IAAA,oBAAa,EAAC,QAAQ,CAAC,CAAC;QAClC,MAAM,kBAAkB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACpC,CAAC,CAAC;AACH,CAAC,CAAC;AA3CW,QAAA,wBAAwB,4BA2CnC"}
@@ -0,0 +1,6 @@
1
+ import type { NodeHTTPHandlerOptions, NodeHTTPRequest, NodeHTTPResponse } from "@trpc/server/dist/adapters/node-http";
2
+ import type { OpenApiRouter } from "../../types";
3
+ export type CreateOpenApiNodeHttpHandlerOptions<TRouter extends OpenApiRouter, TRequest extends NodeHTTPRequest, TResponse extends NodeHTTPResponse> = Pick<NodeHTTPHandlerOptions<TRouter, TRequest, TResponse>, "router" | "createContext" | "responseMeta" | "onError" | "maxBodySize">;
4
+ export type OpenApiNextFunction = () => void;
5
+ export declare const createOpenApiNodeHttpHandler: <TRouter extends OpenApiRouter, TRequest extends NodeHTTPRequest, TResponse extends NodeHTTPResponse>(opts: CreateOpenApiNodeHttpHandlerOptions<TRouter, TRequest, TResponse>) => (req: TRequest, res: TResponse, next?: OpenApiNextFunction) => Promise<void>;
6
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../../src/adapters/node-http/core.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACX,sBAAsB,EACtB,eAAe,EACf,gBAAgB,EAChB,MAAM,sCAAsC,CAAC;AAK9C,OAAO,KAAK,EAIX,aAAa,EAEb,MAAM,aAAa,CAAC;AAerB,MAAM,MAAM,mCAAmC,CAC9C,OAAO,SAAS,aAAa,EAC7B,QAAQ,SAAS,eAAe,EAChC,SAAS,SAAS,gBAAgB,IAC/B,IAAI,CACP,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,EACpD,QAAQ,GAAG,eAAe,GAAG,cAAc,GAAG,SAAS,GAAG,aAAa,CACvE,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,MAAM,IAAI,CAAC;AAE7C,eAAO,MAAM,4BAA4B,GACxC,OAAO,SAAS,aAAa,EAC7B,QAAQ,SAAS,eAAe,EAChC,SAAS,SAAS,gBAAgB,QAE5B,mCAAmC,CAAC,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,WAYpD,QAAQ,OAAO,SAAS,SAAS,mBAAmB,kBA8IvE,CAAC"}