next-openapi-gen 0.0.15 → 0.0.17

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/README.md CHANGED
@@ -1,125 +1,155 @@
1
- # next-openapi-gen
2
-
3
- **next-openapi-gen** super fast and easy way to generate OpenAPI 3.0 documentation automatically from API routes in a Next.js 14.
4
-
5
- With support for multiple user interfaces next-openapi-gen makes documenting your API a breeze!
6
-
7
- ## Prerequisites
8
-
9
- - Nextjs >= 14
10
- - Node >= 18
11
-
12
- ## Supported interfaces
13
-
14
- - Swagger
15
- - Redoc
16
- - Stoplight Elements
17
- - RapiDoc
18
-
19
- ## Features
20
-
21
- - **Automatic OpenAPI Generation**: Generate OpenAPI 3.0 documentation from your Next.js routes, automatically parsing TypeScript types for parameters, request bodies and responses.
22
- - **TypeScript Type Scanning**: Automatically resolve TypeScript types for params, body, and responses based on your API endpoint's TypeScript definitions. Field comments in TypeScript types are reflected as descriptions in the OpenAPI schema.
23
- - **JSDoc-Based Documentation (Optional)**: Document API routes with JSDoc comments, including tags like `@openapi`, `@auth`, `@desc`, `@params`, `@body`, and `@response` to easily define route metadata.
24
- - **UI Interface Options**: Choose between `Swagger UI`, `Redoc`, `Stoplight Elements` or `RapiDoc` to visualize your API documentation. Customize the interface to fit your preferences.
25
- - **Real-time Documentation**: As your API evolves, regenerate the OpenAPI documentation with a single command, ensuring your documentation is always up to date.
26
- - **Easy configuration**: Customize generator behavior using the `next.openapi.json` configuration file, allowing for quick adjustments without modifying the code.
27
-
28
- ## Installation
29
-
30
- ```bash
31
- yarn add next-openapi-gen
32
- ```
33
-
34
- ## Usage
35
-
36
- ### Step 1: Initialize Configuration and Setup
37
-
38
- Run the following command to generate the `next.openapi.json` configuration file and automatically set up Swagger UI with `/api-docs` routes:
39
-
40
- ```bash
41
- npx next-openapi-gen init --ui swagger --docs-url api-docs
42
- ```
43
-
44
- Parameters:
45
- - **ui**: `swagger` | `redoc` | `stoplight` | `rapidoc`
46
- - **docs-url**: url on which api docs will be visible
47
-
48
- This command does the following:
49
-
50
- - Generates a `next.openapi.json` file, which stores the OpenAPI configuration for your project.
51
- - Installs Swagger UI to provide an API documentation interface.
52
- - Adds an `/api-docs` route in the Next.js app for visualizing the generated OpenAPI documentation.
53
-
54
- ### Step 2: Add JSDoc Comments to Your API Routes
55
-
56
- Annotate your API routes using JSDoc comments. Here's an example:
57
-
58
- ```typescript
59
- //app/api/auth/reset-password/route.ts
60
-
61
- import { type NextRequest } from "next/server";
62
-
63
- type ResetPasswordParams = {
64
- token: string; // Token for resetting the password
65
- };
66
-
67
- type ResetPasswordBody = {
68
- password: string; // The new password for the user
69
- };
70
-
71
- type ResetPasswordResponse = {
72
- message: string; // Confirmation message that password has been reset
73
- };
74
-
75
- /**
76
- * Reset the user's password.
77
- * @auth: bearer
78
- * @desc: Allows users to reset their password using a reset token.
79
- * @params: ResetPasswordParams
80
- * @body: ResetPasswordBody
81
- * @response: ResetPasswordResponse
82
- */
83
- export async function POST(req: Request) {
84
- const searchParams = req.nextUrl.searchParams;
85
-
86
- const token = searchParams.get("token"); // Token from query params
87
- const { password } = await req.json(); // New password from request body
88
-
89
- // Logic to reset the user's password
90
-
91
- return Response.json({ message: "Password has been reset" });
92
- }
93
- ```
94
-
95
- - `@openapi`: Marks the route for inclusion in the OpenAPI specification.
96
- - `@auth`: Specifies authentication type used for API route (`basic`, `bearer`, `apikey`)
97
- - `@desc`: Provides a detailed description of the API route.
98
- - `@params`: Specifies the TypeScript interface or Zod schema for the query parameters.
99
- - `@body`: Specifies the TypeScript interface or Zod schema for the request body.
100
- - `@response`: Specifies the TypeScript interface or Zod schema for the response.
101
-
102
- ### Step 3: Generate the OpenAPI Specification
103
-
104
- Run the following command to generate the OpenAPI schema based on your API routes:
105
-
106
- ```bash
107
- npx next-openapi-gen generate
108
- ```
109
-
110
- This command processes all your API routes, extracts the necessary information from JSDoc comments, and generates the OpenAPI schema, typically saved to a `swagger.json` file in the `public` folder.
111
-
112
- ### Step 4: View API Documentation
113
-
114
- With the `/api-docs` route generated from the init command, you can now access your API documentation through Swagger UI by navigating to `http://localhost:3000/api-docs`.
115
-
116
- ## Configuration Options
117
-
118
- The `next.openapi.json` file allows you to configure the behavior of the OpenAPI generator, including options such as:
119
-
120
- - **apiDir**: (default: `./src/app/api`) The directory where your API routes are stored.
121
- - **schemaDir**: (default: `./src`) The directory where your schema definitions are stored.
122
- - **docsUrl**: (default: `./api-docs`) Route where OpenAPI UI is available.
123
- - **ui**: (default: `swagger`) OpenAPI UI interface.
124
- - **outputFile**: (default: `./swagger.json`) The file where the generated OpenAPI specification will be saved in `public` folder.
125
- - **includeOpenApiRoutes**: (default: `false`) When `true`, the generator will only include routes that have the `@openapi` tag in their JSDoc comments.
1
+ # next-openapi-gen
2
+
3
+ **next-openapi-gen** super fast and easy way to generate OpenAPI 3.0 documentation automatically from API routes in a Next.js 14.
4
+
5
+ With support for multiple user interfaces next-openapi-gen makes documenting your API a breeze!
6
+
7
+ ## Prerequisites
8
+
9
+ - Nextjs >= 14
10
+ - Node >= 18
11
+
12
+ ## Supported interfaces
13
+
14
+ - Swagger
15
+ - Redoc
16
+ - Stoplight Elements
17
+ - RapiDoc
18
+
19
+ ## Features
20
+
21
+ - **Automatic OpenAPI Generation**: Generate OpenAPI 3.0 documentation from your Next.js routes, automatically parsing TypeScript types for parameters, request bodies and responses.
22
+ - **TypeScript Type Scanning**: Automatically resolve TypeScript types for params, body, and responses based on your API endpoint's TypeScript definitions. Field comments in TypeScript types are reflected as descriptions in the OpenAPI schema.
23
+ - **JSDoc-Based Documentation (Optional)**: Document API routes with JSDoc comments, including tags like `@openapi`, `@auth`, `@desc`, `@params`, `@body`, and `@response` to easily define route metadata.
24
+ - **UI Interface Options**: Choose between `Swagger UI`, `Redoc`, `Stoplight Elements` or `RapiDoc` to visualize your API documentation. Customize the interface to fit your preferences.
25
+ - **Real-time Documentation**: As your API evolves, regenerate the OpenAPI documentation with a single command, ensuring your documentation is always up to date.
26
+ - **Easy configuration**: Customize generator behavior using the `next.openapi.json` configuration file, allowing for quick adjustments without modifying the code.
27
+
28
+ ![Demo File](https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/demo.gif)
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ yarn add next-openapi-gen
34
+ ```
35
+
36
+ ## Usage
37
+
38
+ ### Step 1: Initialize Configuration and Setup
39
+
40
+ Run the following command to generate the `next.openapi.json` configuration file and automatically set up Swagger UI with `/api-docs` routes:
41
+
42
+ ```bash
43
+ npx next-openapi-gen init --ui swagger --docs-url api-docs
44
+ ```
45
+
46
+ Parameters:
47
+ - **ui**: `swagger` | `redoc` | `stoplight` | `rapidoc`
48
+ - **docs-url**: url on which api docs will be visible
49
+
50
+ This command does the following:
51
+
52
+ - Generates a `next.openapi.json` file, which stores the OpenAPI configuration for your project.
53
+ - Installs Swagger UI to provide an API documentation interface.
54
+ - Adds an `/api-docs` route in the Next.js app for visualizing the generated OpenAPI documentation.
55
+
56
+ ### Step 2: Add JSDoc Comments to Your API Routes
57
+
58
+ Annotate your API routes using JSDoc comments. Here's an example:
59
+
60
+ ```typescript
61
+ //app/api/auth/reset-password/route.ts
62
+
63
+ import { type NextRequest } from "next/server";
64
+
65
+ type ResetPasswordParams = {
66
+ token: string; // Token for resetting the password
67
+ };
68
+
69
+ type ResetPasswordBody = {
70
+ password: string; // The new password for the user
71
+ };
72
+
73
+ type ResetPasswordResponse = {
74
+ message: string; // Confirmation message that password has been reset
75
+ };
76
+
77
+ /**
78
+ * Reset the user's password.
79
+ * @auth: bearer
80
+ * @desc: Allows users to reset their password using a reset token.
81
+ * @params: ResetPasswordParams
82
+ * @body: ResetPasswordBody
83
+ * @response: ResetPasswordResponse
84
+ */
85
+ export async function POST(req: Request) {
86
+ const searchParams = req.nextUrl.searchParams;
87
+
88
+ const token = searchParams.get("token"); // Token from query params
89
+ const { password } = await req.json(); // New password from request body
90
+
91
+ // Logic to reset the user's password
92
+
93
+ return Response.json({ message: "Password has been reset" });
94
+ }
95
+ ```
96
+
97
+ - `@openapi`: Marks the route for inclusion in the OpenAPI specification.
98
+ - `@auth`: Specifies authentication type used for API route (`basic`, `bearer`, `apikey`)
99
+ - `@desc`: Provides a detailed description of the API route.
100
+ - `@params`: Specifies the TypeScript interface for the query parameters.
101
+ - `@body`: Specifies the TypeScript interface for the request body.
102
+ - `@response`: Specifies the TypeScript interface for the response.
103
+
104
+ ### Step 3: Generate the OpenAPI Specification
105
+
106
+ Run the following command to generate the OpenAPI schema based on your API routes:
107
+
108
+ ```bash
109
+ npx next-openapi-gen generate
110
+ ```
111
+
112
+ This command processes all your API routes, extracts the necessary information from JSDoc comments, and generates the OpenAPI schema, typically saved to a `swagger.json` file in the `public` folder.
113
+
114
+ ### Step 4: View API Documentation
115
+
116
+ With the `/api-docs` route generated from the init command, you can now access your API documentation through Swagger UI by navigating to `http://localhost:3000/api-docs`.
117
+
118
+ ## Configuration Options
119
+
120
+ The `next.openapi.json` file allows you to configure the behavior of the OpenAPI generator, including options such as:
121
+
122
+ - **apiDir**: (default: `./src/app/api`) The directory where your API routes are stored.
123
+ - **schemaDir**: (default: `./src`) The directory where your schema definitions are stored.
124
+ - **docsUrl**: (default: `./api-docs`) Route where OpenAPI UI is available.
125
+ - **ui**: (default: `swagger`) OpenAPI UI interface.
126
+ - **outputFile**: (default: `./swagger.json`) The file where the generated OpenAPI specification will be saved in `public` folder.
127
+ - **includeOpenApiRoutes**: (default: `false`) When `true`, the generator will only include routes that have the `@openapi` tag in their JSDoc comments.
128
+
129
+ ## Interface providers
130
+
131
+ <div align="center">
132
+ <table>
133
+ <thead>
134
+ <th>SwaggerUI</th>
135
+ <th>Redoc</th>
136
+ <th>Stoplight Elements</th>
137
+ <th>RapiDoc</th>
138
+ </thead>
139
+ <tbody>
140
+ <tr>
141
+ <td>
142
+ <img width="320" alt="swagger" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/swagger.png" alt-text="swagger">
143
+ </td>
144
+ <td>
145
+ <img width="320" alt="redoc" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/redoc.png" alt-text="redoc">
146
+ </td>
147
+ <td>
148
+ <img width="320" alt="stoplight" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/stoplight.png" alt-text="stoplight">
149
+ </td>
150
+ <td>
151
+ <img width="320" alt="rapidoc" src="https://raw.githubusercontent.com/tazo90/next-openapi-gen/refs/heads/main/assets/rapidoc.png" alt-text="rapidoc">
152
+ </td>
153
+ </tr>
154
+ </tbody>
155
+ </table>
@@ -89,7 +89,8 @@ export class RouteProcessor {
89
89
  ];
90
90
  }
91
91
  if (params) {
92
- definition.parameters = params;
92
+ definition.parameters =
93
+ this.schemaProcessor.createRequestParamsSchema(params);
93
94
  }
94
95
  // Add request body
95
96
  if (MUTATION_HTTP_METHODS.includes(method.toUpperCase())) {
@@ -5,102 +5,203 @@ import traverse from "@babel/traverse";
5
5
  import * as t from "@babel/types";
6
6
  export class SchemaProcessor {
7
7
  schemaDir;
8
+ typeDefinitions = {};
9
+ openapiDefinitions = {};
10
+ contentType = "";
8
11
  constructor(schemaDir) {
9
12
  this.schemaDir = path.resolve(schemaDir);
10
13
  }
11
- findSchemaDefinition(schemaName) {
14
+ findSchemaDefinition(schemaName, contentType) {
12
15
  let schemaNode = null;
13
- this.scanSchemaDir(this.schemaDir, schemaName, (node) => {
14
- schemaNode = node;
15
- });
16
+ // assign type that is actually processed
17
+ this.contentType = contentType;
18
+ this.scanSchemaDir(this.schemaDir, schemaName);
16
19
  return schemaNode;
17
20
  }
18
- scanSchemaDir(dir, schemaName, callback) {
21
+ scanSchemaDir(dir, schemaName) {
19
22
  const files = fs.readdirSync(dir);
20
23
  files.forEach((file) => {
21
24
  const filePath = path.join(dir, file);
22
25
  const stat = fs.statSync(filePath);
23
26
  if (stat.isDirectory()) {
24
- this.scanSchemaDir(filePath, schemaName, callback);
27
+ this.scanSchemaDir(filePath, schemaName);
25
28
  }
26
29
  else if (file.endsWith(".ts")) {
27
- this.processSchemaFile(filePath, schemaName, callback);
30
+ this.processSchemaFile(filePath, schemaName);
28
31
  }
29
32
  });
30
33
  }
31
- processSchemaFile(filePath, schemaName, callback) {
32
- const content = fs.readFileSync(filePath, "utf-8");
33
- const ast = parse(content, {
34
- sourceType: "module",
35
- plugins: ["typescript", "decorators-legacy"],
36
- });
34
+ collectTypeDefinitions(ast, schemaName) {
37
35
  traverse.default(ast, {
38
36
  VariableDeclarator: (path) => {
39
37
  if (t.isIdentifier(path.node.id, { name: schemaName })) {
40
- callback(path.node.init || path.node);
38
+ const name = path.node.id.name;
39
+ this.typeDefinitions[name] = path.node.init || path.node;
41
40
  }
42
41
  },
43
42
  TSTypeAliasDeclaration: (path) => {
44
43
  if (t.isIdentifier(path.node.id, { name: schemaName })) {
45
- callback(path.node.typeAnnotation);
44
+ const name = path.node.id.name;
45
+ this.typeDefinitions[name] = path.node.typeAnnotation;
46
46
  }
47
47
  },
48
48
  TSInterfaceDeclaration: (path) => {
49
49
  if (t.isIdentifier(path.node.id, { name: schemaName })) {
50
- callback(path.node);
50
+ const name = path.node.id.name;
51
+ this.typeDefinitions[name] = path.node;
52
+ }
53
+ },
54
+ TSEnumDeclaration: (path) => {
55
+ if (t.isIdentifier(path.node.id, { name: schemaName })) {
56
+ const name = path.node.id.name;
57
+ this.typeDefinitions[name] = path.node;
51
58
  }
52
59
  },
53
60
  });
54
61
  }
55
- extractTypesFromSchema(schema, dataType) {
56
- const result = dataType === "params" ? [] : {};
57
- const handleProperty = (property) => {
58
- const key = property.key.name;
59
- const typeAnnotation = property.typeAnnotation?.typeAnnotation?.type;
60
- const type = this.getTypeFromAnnotation(typeAnnotation);
61
- const isOptional = !!property.optional; // check if property is optional
62
- let description = "";
63
- // get comments for field
64
- if (property.trailingComments && property.trailingComments.length) {
65
- description = property.trailingComments[0].value.trim(); // get first comment
62
+ resolveType(typeName) {
63
+ const typeNode = this.typeDefinitions[typeName.toString()];
64
+ if (!typeNode)
65
+ return {};
66
+ if (t.isTSEnumDeclaration(typeNode)) {
67
+ const enumValues = this.processEnum(typeNode);
68
+ return enumValues;
69
+ }
70
+ if (t.isTSTypeLiteral(typeNode) || t.isTSInterfaceBody(typeNode)) {
71
+ const properties = {};
72
+ if ("members" in typeNode) {
73
+ (typeNode.members || []).forEach((member) => {
74
+ if (t.isTSPropertySignature(member) && t.isIdentifier(member.key)) {
75
+ const propName = member.key.name;
76
+ const options = this.getPropertyOptions(member);
77
+ const property = {
78
+ ...this.resolveTSNodeType(member.typeAnnotation?.typeAnnotation),
79
+ ...options,
80
+ };
81
+ properties[propName] = property;
82
+ }
83
+ });
66
84
  }
67
- const field = {
68
- type: type,
69
- description: description,
85
+ return { type: "object", properties };
86
+ }
87
+ if (t.isTSArrayType(typeNode)) {
88
+ return {
89
+ type: "array",
90
+ items: this.resolveTSNodeType(typeNode.elementType),
91
+ };
92
+ }
93
+ return {};
94
+ }
95
+ resolveTSNodeType(node) {
96
+ if (t.isTSStringKeyword(node))
97
+ return { type: "string" };
98
+ if (t.isTSNumberKeyword(node))
99
+ return { type: "number" };
100
+ if (t.isTSBooleanKeyword(node))
101
+ return { type: "boolean" };
102
+ if (t.isTSTypeReference(node) && t.isIdentifier(node.typeName)) {
103
+ const typeName = node.typeName.name;
104
+ // Find type definition
105
+ this.findSchemaDefinition(typeName, this.contentType);
106
+ return this.resolveType(node.typeName.name);
107
+ }
108
+ if (t.isTSArrayType(node)) {
109
+ return {
110
+ type: "array",
111
+ items: this.resolveTSNodeType(node.elementType),
70
112
  };
71
- if (dataType === "params") {
113
+ }
114
+ if (t.isTSTypeLiteral(node)) {
115
+ const properties = {};
116
+ node.members.forEach((member) => {
117
+ if (t.isTSPropertySignature(member) && t.isIdentifier(member.key)) {
118
+ const propName = member.key.name;
119
+ properties[propName] = this.resolveTSNodeType(member.typeAnnotation?.typeAnnotation);
120
+ }
121
+ });
122
+ return { type: "object", properties };
123
+ }
124
+ return {};
125
+ }
126
+ processSchemaFile(filePath, schemaName) {
127
+ // Recognizes different elements of TS like variable, type, interface, enum
128
+ const content = fs.readFileSync(filePath, "utf-8");
129
+ const ast = parse(content, {
130
+ sourceType: "module",
131
+ plugins: ["typescript", "decorators-legacy"],
132
+ });
133
+ this.collectTypeDefinitions(ast, schemaName);
134
+ const definition = this.resolveType(schemaName);
135
+ this.openapiDefinitions[schemaName] = definition;
136
+ return definition;
137
+ }
138
+ processEnum(enumNode) {
139
+ // Initialization OpenAPI enum object
140
+ const enumSchema = {
141
+ type: "string",
142
+ enum: [],
143
+ };
144
+ // Iterate throught enum members
145
+ enumNode.members.forEach((member) => {
146
+ if (t.isTSEnumMember(member)) {
72
147
  // @ts-ignore
73
- result.push({
74
- name: key,
75
- in: "query",
76
- schema: field,
77
- required: !isOptional,
78
- });
79
- }
80
- else {
81
- result[key] = field;
148
+ const name = member.id?.name;
149
+ // @ts-ignore
150
+ const value = member.initializer?.value;
151
+ let type = member.initializer?.type;
152
+ if (type === "NumericLiteral") {
153
+ enumSchema.type = "number";
154
+ }
155
+ const targetValue = value || name;
156
+ enumSchema.enum.push(targetValue);
82
157
  }
83
- };
84
- if (schema.body?.body) {
85
- schema.body.body.forEach(handleProperty);
158
+ });
159
+ return enumSchema;
160
+ }
161
+ getPropertyOptions(node) {
162
+ const key = node.key.name;
163
+ const isOptional = !!node.optional; // check if property is optional
164
+ const typeName = node.typeAnnotation?.typeAnnotation?.typeName?.name;
165
+ let description = null;
166
+ // get comments for field
167
+ if (node.trailingComments && node.trailingComments.length) {
168
+ description = node.trailingComments[0].value.trim(); // get first comment
169
+ }
170
+ const options = {};
171
+ if (description) {
172
+ options.description = description;
86
173
  }
87
- if (schema.type === "TSTypeLiteral" && schema.members) {
88
- schema.members.forEach(handleProperty);
174
+ if (this.contentType === "params") {
175
+ options.required = !isOptional;
89
176
  }
90
- return result;
177
+ else if (this.contentType === "body") {
178
+ options.nullable = isOptional;
179
+ }
180
+ return options;
91
181
  }
92
- getTypeFromAnnotation(type) {
93
- switch (type) {
94
- case "TSStringKeyword":
95
- return "string";
96
- case "TSNumberKeyword":
97
- return "number";
98
- case "TSBooleanKeyword":
99
- return "boolean";
100
- // Add other cases as needed.
101
- default:
102
- return "object"; // fallback to object for unknown types
182
+ createRequestParamsSchema(params) {
183
+ const queryParams = [];
184
+ if (params.properties) {
185
+ for (let [name, value] of Object.entries(params.properties)) {
186
+ const param = {
187
+ in: "query",
188
+ name,
189
+ schema: {
190
+ type: value.type,
191
+ },
192
+ required: value.required,
193
+ };
194
+ if (value.enum) {
195
+ param.schema.enum = value.enum;
196
+ }
197
+ if (value.description) {
198
+ param.description = value.description;
199
+ param.schema.description = value.description;
200
+ }
201
+ queryParams.push(param);
202
+ }
103
203
  }
204
+ return queryParams;
104
205
  }
105
206
  createRequestBodySchema(body) {
106
207
  return {
@@ -120,32 +221,19 @@ export class SchemaProcessor {
120
221
  description: "Successful response",
121
222
  content: {
122
223
  "application/json": {
123
- schema: {
124
- type: "object",
125
- properties: responses,
126
- },
224
+ schema: responses,
127
225
  },
128
226
  },
129
227
  },
130
228
  };
131
229
  }
132
230
  getSchemaContent({ paramsType, bodyType, responseType }) {
133
- const paramsSchema = paramsType
134
- ? this.findSchemaDefinition(paramsType)
135
- : null;
136
- const bodySchema = bodyType ? this.findSchemaDefinition(bodyType) : null;
137
- const responseSchema = responseType
138
- ? this.findSchemaDefinition(responseType)
139
- : null;
140
- let params = paramsSchema
141
- ? this.extractTypesFromSchema(paramsSchema, "params")
142
- : [];
143
- let body = bodySchema
144
- ? this.extractTypesFromSchema(bodySchema, "body")
145
- : {};
146
- let responses = responseSchema
147
- ? this.extractTypesFromSchema(responseSchema, "responses")
148
- : {};
231
+ this.findSchemaDefinition(paramsType, "params");
232
+ this.findSchemaDefinition(bodyType, "body");
233
+ this.findSchemaDefinition(responseType, "response");
234
+ const params = this.openapiDefinitions[paramsType];
235
+ const body = this.openapiDefinitions[bodyType];
236
+ const responses = this.openapiDefinitions[responseType];
149
237
  return {
150
238
  params,
151
239
  body,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "next-openapi-gen",
3
- "version": "0.0.15",
3
+ "version": "0.0.17",
4
4
  "description": "Super fast and easy way to generate OpenAPI documentation automatically from API routes in a NextJS 14",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -26,7 +26,8 @@
26
26
  "openapi",
27
27
  "swagger",
28
28
  "docs",
29
- "api"
29
+ "api",
30
+ "redoc"
30
31
  ],
31
32
  "publishConfig": {
32
33
  "access": "public"