@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
@@ -0,0 +1,162 @@
1
+ /* eslint-disable @typescript-eslint/ban-types */
2
+ import { initTRPC } from '@trpc/server';
3
+ import { NextApiRequest, NextApiResponse } from 'next';
4
+ import { z } from 'zod';
5
+
6
+ import {
7
+ CreateOpenApiNextHandlerOptions,
8
+ OpenApiMeta,
9
+ OpenApiResponse,
10
+ OpenApiRouter,
11
+ createOpenApiNextHandler,
12
+ } from '../../src';
13
+
14
+ const createContextMock = jest.fn();
15
+ const responseMetaMock = jest.fn();
16
+ const onErrorMock = jest.fn();
17
+
18
+ const clearMocks = () => {
19
+ createContextMock.mockClear();
20
+ responseMetaMock.mockClear();
21
+ onErrorMock.mockClear();
22
+ };
23
+
24
+ const createOpenApiNextHandlerCaller = <TRouter extends OpenApiRouter>(
25
+ handlerOpts: CreateOpenApiNextHandlerOptions<TRouter>,
26
+ ) => {
27
+ const openApiNextHandler = createOpenApiNextHandler({
28
+ router: handlerOpts.router,
29
+ createContext: handlerOpts.createContext ?? createContextMock,
30
+ responseMeta: handlerOpts.responseMeta ?? responseMetaMock,
31
+ onError: handlerOpts.onError ?? onErrorMock,
32
+ } as any);
33
+
34
+ return (req: { method: string; query: Record<string, any>; body?: any }) => {
35
+ return new Promise<{
36
+ statusCode: number;
37
+ headers: Record<string, any>;
38
+ body: OpenApiResponse | undefined;
39
+ /* eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor */
40
+ }>(async (resolve, reject) => {
41
+ const headers = new Map();
42
+ let body: any;
43
+ const res: any = {
44
+ statusCode: undefined,
45
+ setHeader: (key: string, value: any) => headers.set(key, value),
46
+ end: (data: string) => {
47
+ body = JSON.parse(data);
48
+ },
49
+ };
50
+
51
+ try {
52
+ await openApiNextHandler(
53
+ req as unknown as NextApiRequest,
54
+ res as unknown as NextApiResponse,
55
+ );
56
+ resolve({
57
+ statusCode: res.statusCode,
58
+ headers: Object.fromEntries(headers.entries()),
59
+ body,
60
+ });
61
+ } catch (error) {
62
+ reject(error);
63
+ }
64
+ });
65
+ };
66
+ };
67
+
68
+ const t = initTRPC.meta<OpenApiMeta>().context<any>().create();
69
+
70
+ describe('next adapter', () => {
71
+ afterEach(() => {
72
+ clearMocks();
73
+ });
74
+
75
+ test('with valid routes', async () => {
76
+ const appRouter = t.router({
77
+ sayHelloQuery: t.procedure
78
+ .meta({ openapi: { method: 'GET', path: '/say-hello' } })
79
+ .input(z.object({ name: z.string() }))
80
+ .output(z.object({ greeting: z.string() }))
81
+ .query(({ input }) => ({ greeting: `Hello ${input.name}!` })),
82
+ sayHelloMutation: t.procedure
83
+ .meta({ openapi: { method: 'POST', path: '/say-hello' } })
84
+ .input(z.object({ name: z.string() }))
85
+ .output(z.object({ greeting: z.string() }))
86
+ .mutation(({ input }) => ({ greeting: `Hello ${input.name}!` })),
87
+ sayHelloSlash: t.procedure
88
+ .meta({ openapi: { method: 'GET', path: '/say/hello' } })
89
+ .input(z.object({ name: z.string() }))
90
+ .output(z.object({ greeting: z.string() }))
91
+ .query(({ input }) => ({ greeting: `Hello ${input.name}!` })),
92
+ });
93
+
94
+ const openApiNextHandlerCaller = createOpenApiNextHandlerCaller({
95
+ router: appRouter,
96
+ });
97
+
98
+ {
99
+ const res = await openApiNextHandlerCaller({
100
+ method: 'GET',
101
+ query: { trpc: 'say-hello', name: 'James' },
102
+ });
103
+
104
+ expect(res.statusCode).toBe(200);
105
+ expect(res.body).toEqual({ greeting: 'Hello James!' });
106
+ expect(createContextMock).toHaveBeenCalledTimes(1);
107
+ expect(responseMetaMock).toHaveBeenCalledTimes(1);
108
+ expect(onErrorMock).toHaveBeenCalledTimes(0);
109
+
110
+ clearMocks();
111
+ }
112
+ {
113
+ const res = await openApiNextHandlerCaller({
114
+ method: 'POST',
115
+ query: { trpc: 'say-hello' },
116
+ body: { name: 'James' },
117
+ });
118
+
119
+ expect(res.statusCode).toBe(200);
120
+ expect(res.body).toEqual({ greeting: 'Hello James!' });
121
+ expect(createContextMock).toHaveBeenCalledTimes(1);
122
+ expect(responseMetaMock).toHaveBeenCalledTimes(1);
123
+ expect(onErrorMock).toHaveBeenCalledTimes(0);
124
+
125
+ clearMocks();
126
+ }
127
+ {
128
+ const res = await openApiNextHandlerCaller({
129
+ method: 'GET',
130
+ query: { trpc: ['say', 'hello'], name: 'James' },
131
+ });
132
+
133
+ expect(res.statusCode).toBe(200);
134
+ expect(res.body).toEqual({ greeting: 'Hello James!' });
135
+ expect(createContextMock).toHaveBeenCalledTimes(1);
136
+ expect(responseMetaMock).toHaveBeenCalledTimes(1);
137
+ expect(onErrorMock).toHaveBeenCalledTimes(0);
138
+ }
139
+ });
140
+
141
+ test('with invalid path', async () => {
142
+ const appRouter = t.router({});
143
+
144
+ const openApiNextHandlerCaller = createOpenApiNextHandlerCaller({
145
+ router: appRouter,
146
+ });
147
+
148
+ const res = await openApiNextHandlerCaller({
149
+ method: 'GET',
150
+ query: {},
151
+ });
152
+
153
+ expect(res.statusCode).toBe(500);
154
+ expect(res.body).toEqual({
155
+ message: 'Query "trpc" not found - is the `trpc-openapi` file named `[...trpc].ts`?',
156
+ code: 'INTERNAL_SERVER_ERROR',
157
+ });
158
+ expect(createContextMock).toHaveBeenCalledTimes(0);
159
+ expect(responseMetaMock).toHaveBeenCalledTimes(0);
160
+ expect(onErrorMock).toHaveBeenCalledTimes(1);
161
+ });
162
+ });