bxo 0.0.5-dev.70 → 0.0.5-dev.71
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 +71 -0
- package/example/index.ts +136 -3
- package/example/openapi-example.ts +132 -0
- package/package.json +1 -1
- package/plugins/openapi.ts +78 -5
package/README.md
CHANGED
|
@@ -93,6 +93,76 @@ app.use(cors({
|
|
|
93
93
|
}));
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
### OpenAPI Plugin
|
|
97
|
+
|
|
98
|
+
The OpenAPI plugin automatically generates OpenAPI 3.0 documentation with support for tags, security schemes, and comprehensive route metadata:
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import { openapi } from "./plugins";
|
|
102
|
+
|
|
103
|
+
app.use(openapi({
|
|
104
|
+
path: "/docs", // Swagger UI endpoint
|
|
105
|
+
jsonPath: "/openapi.json", // OpenAPI JSON endpoint
|
|
106
|
+
defaultTags: ["API"], // Default tags for routes
|
|
107
|
+
securitySchemes: { // Define security schemes
|
|
108
|
+
bearerAuth: {
|
|
109
|
+
type: "http",
|
|
110
|
+
scheme: "bearer",
|
|
111
|
+
bearerFormat: "JWT",
|
|
112
|
+
description: "JWT token for authentication"
|
|
113
|
+
},
|
|
114
|
+
apiKeyAuth: {
|
|
115
|
+
type: "apiKey",
|
|
116
|
+
in: "header",
|
|
117
|
+
name: "X-API-Key",
|
|
118
|
+
description: "API key for authentication"
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
globalSecurity: [ // Global security requirements
|
|
122
|
+
{ bearerAuth: [] },
|
|
123
|
+
{ apiKeyAuth: [] }
|
|
124
|
+
],
|
|
125
|
+
openapiConfig: { // Additional OpenAPI config
|
|
126
|
+
info: {
|
|
127
|
+
title: "My API",
|
|
128
|
+
version: "1.0.0",
|
|
129
|
+
description: "API description"
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}));
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### Route Metadata
|
|
136
|
+
|
|
137
|
+
Routes can include detailed metadata for better OpenAPI documentation:
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
app.get("/users/:id", (ctx) => {
|
|
141
|
+
const id = ctx.params.id
|
|
142
|
+
return { user: { id, name: "John Doe" } }
|
|
143
|
+
}, {
|
|
144
|
+
detail: {
|
|
145
|
+
tags: ["Users"], // Route tags for grouping
|
|
146
|
+
summary: "Get user by ID", // Operation summary
|
|
147
|
+
description: "Retrieve user details", // Detailed description
|
|
148
|
+
security: [{ bearerAuth: [] }], // Route-specific security
|
|
149
|
+
params: { // Parameter documentation
|
|
150
|
+
id: z.string().describe("User ID")
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### Supported Metadata Fields
|
|
157
|
+
|
|
158
|
+
- `tags`: Array of tags for grouping operations
|
|
159
|
+
- `summary`: Short description of the operation
|
|
160
|
+
- `description`: Detailed description of the operation
|
|
161
|
+
- `security`: Security requirements for the route
|
|
162
|
+
- `params`: Path parameter schemas and descriptions
|
|
163
|
+
- `query`: Query parameter schemas
|
|
164
|
+
- `hidden`: Set to `true` to exclude from OpenAPI docs
|
|
165
|
+
|
|
96
166
|
### Creating Custom Plugins
|
|
97
167
|
|
|
98
168
|
Plugins are just BXO instances with lifecycle hooks:
|
|
@@ -149,6 +219,7 @@ bun run ./example/cors-example.ts
|
|
|
149
219
|
Check out the `example/` directory for more usage examples:
|
|
150
220
|
|
|
151
221
|
- `cors-example.ts` - Demonstrates CORS plugin and lifecycle hooks
|
|
222
|
+
- `openapi-example.ts` - Demonstrates OpenAPI plugin with tags and security
|
|
152
223
|
- `index.ts` - Basic routing example
|
|
153
224
|
|
|
154
225
|
This project was created using `bun init` in bun v1.2.3. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
package/example/index.ts
CHANGED
|
@@ -8,6 +8,7 @@ async function main() {
|
|
|
8
8
|
bxo.default("/", index);
|
|
9
9
|
bxo.default("/*", index);
|
|
10
10
|
|
|
11
|
+
// API routes with comprehensive metadata
|
|
11
12
|
bxo.get("/api/get/:id", (ctx) => {
|
|
12
13
|
return new Response(ctx.params.id + ctx.query.name, {
|
|
13
14
|
headers: {
|
|
@@ -23,7 +24,16 @@ async function main() {
|
|
|
23
24
|
name: z.string()
|
|
24
25
|
})
|
|
25
26
|
},
|
|
27
|
+
detail: {
|
|
28
|
+
tags: ["API"],
|
|
29
|
+
summary: "Get data by ID",
|
|
30
|
+
description: "Retrieve data using an ID and name query parameter",
|
|
31
|
+
params: {
|
|
32
|
+
id: z.string().describe("Unique identifier for the data")
|
|
33
|
+
}
|
|
34
|
+
}
|
|
26
35
|
});
|
|
36
|
+
|
|
27
37
|
bxo.post("/api/post", (ctx) => {
|
|
28
38
|
console.log(ctx.body)
|
|
29
39
|
return new Response("Hello" + ctx.body.name, {
|
|
@@ -33,8 +43,10 @@ async function main() {
|
|
|
33
43
|
});
|
|
34
44
|
}, {
|
|
35
45
|
detail: {
|
|
46
|
+
tags: ["API"],
|
|
47
|
+
summary: "Create new data",
|
|
48
|
+
description: "Submit new data with name and avatar file",
|
|
36
49
|
defaultContentType: "multipart/form-data"
|
|
37
|
-
|
|
38
50
|
},
|
|
39
51
|
body: z.object({
|
|
40
52
|
name: z.string(),
|
|
@@ -49,10 +61,131 @@ async function main() {
|
|
|
49
61
|
})
|
|
50
62
|
}
|
|
51
63
|
});
|
|
52
|
-
|
|
64
|
+
|
|
65
|
+
// Additional routes to showcase different features
|
|
66
|
+
bxo.get("/api/users", (ctx) => {
|
|
67
|
+
return ctx.json({ users: ["John", "Jane", "Bob"] });
|
|
68
|
+
}, {
|
|
69
|
+
detail: {
|
|
70
|
+
tags: ["Users"],
|
|
71
|
+
summary: "Get all users",
|
|
72
|
+
description: "Retrieve a list of all users in the system"
|
|
73
|
+
},
|
|
74
|
+
response: {
|
|
75
|
+
200: z.object({
|
|
76
|
+
users: z.array(z.string())
|
|
77
|
+
})
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
bxo.get("/api/users/:id", (ctx) => {
|
|
82
|
+
const id = ctx.params.id;
|
|
83
|
+
return ctx.json({ user: { id, name: "John Doe", email: "john@example.com" } });
|
|
84
|
+
}, {
|
|
85
|
+
detail: {
|
|
86
|
+
tags: ["Users"],
|
|
87
|
+
summary: "Get user by ID",
|
|
88
|
+
description: "Retrieve a specific user by their unique identifier",
|
|
89
|
+
params: {
|
|
90
|
+
id: z.string().describe("User's unique identifier")
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
response: {
|
|
94
|
+
200: z.object({
|
|
95
|
+
user: z.object({
|
|
96
|
+
id: z.string(),
|
|
97
|
+
name: z.string(),
|
|
98
|
+
email: z.string()
|
|
99
|
+
})
|
|
100
|
+
}),
|
|
101
|
+
404: z.object({
|
|
102
|
+
error: z.string()
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
bxo.post("/api/users", (ctx) => {
|
|
108
|
+
const userData = ctx.body;
|
|
109
|
+
return ctx.json({ message: "User created", user: userData });
|
|
110
|
+
}, {
|
|
111
|
+
detail: {
|
|
112
|
+
tags: ["Users"],
|
|
113
|
+
summary: "Create new user",
|
|
114
|
+
description: "Create a new user account with the provided information"
|
|
115
|
+
},
|
|
116
|
+
body: z.object({
|
|
117
|
+
name: z.string().min(1, "Name is required"),
|
|
118
|
+
email: z.string().email("Invalid email format"),
|
|
119
|
+
age: z.number().min(18, "Must be at least 18 years old").optional()
|
|
120
|
+
}),
|
|
121
|
+
response: {
|
|
122
|
+
201: z.object({
|
|
123
|
+
message: z.string(),
|
|
124
|
+
user: z.object({
|
|
125
|
+
name: z.string(),
|
|
126
|
+
email: z.string(),
|
|
127
|
+
age: z.number().optional()
|
|
128
|
+
})
|
|
129
|
+
}),
|
|
130
|
+
400: z.object({
|
|
131
|
+
error: z.string(),
|
|
132
|
+
issues: z.array(z.any()).optional()
|
|
133
|
+
})
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Health check route
|
|
138
|
+
bxo.get("/health", (ctx) => {
|
|
139
|
+
return ctx.json({
|
|
140
|
+
status: "ok",
|
|
141
|
+
timestamp: new Date().toISOString(),
|
|
142
|
+
uptime: process.uptime()
|
|
143
|
+
});
|
|
144
|
+
}, {
|
|
145
|
+
detail: {
|
|
146
|
+
tags: ["System"],
|
|
147
|
+
summary: "Health check",
|
|
148
|
+
description: "Check the health status of the API server"
|
|
149
|
+
},
|
|
150
|
+
response: {
|
|
151
|
+
200: z.object({
|
|
152
|
+
status: z.string(),
|
|
153
|
+
timestamp: z.string(),
|
|
154
|
+
uptime: z.number()
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
// Use OpenAPI plugin with enhanced configuration
|
|
160
|
+
bxo.use(openapi({
|
|
161
|
+
path: "/docs",
|
|
162
|
+
jsonPath: "/openapi.json",
|
|
163
|
+
defaultTags: ["API"],
|
|
164
|
+
securitySchemes: {
|
|
165
|
+
bearerAuth: {
|
|
166
|
+
type: "http",
|
|
167
|
+
scheme: "bearer",
|
|
168
|
+
bearerFormat: "JWT",
|
|
169
|
+
description: "JWT token for authentication"
|
|
170
|
+
},
|
|
171
|
+
apiKeyAuth: {
|
|
172
|
+
type: "apiKey",
|
|
173
|
+
in: "header",
|
|
174
|
+
name: "X-API-Key",
|
|
175
|
+
description: "API key for authentication"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
globalSecurity: [
|
|
179
|
+
{ bearerAuth: [] },
|
|
180
|
+
{ apiKeyAuth: [] }
|
|
181
|
+
],
|
|
182
|
+
openapiConfig: {}
|
|
183
|
+
}));
|
|
184
|
+
|
|
53
185
|
bxo.start();
|
|
54
186
|
console.log(`Server is running on http://localhost:${bxo.server?.port}`);
|
|
55
|
-
|
|
187
|
+
console.log(`OpenAPI documentation available at http://localhost:${bxo.server?.port}/docs`);
|
|
188
|
+
console.log(`OpenAPI JSON available at http://localhost:${bxo.server?.port}/openapi.json`);
|
|
56
189
|
}
|
|
57
190
|
|
|
58
191
|
main();
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import BXO, { z } from "../src";
|
|
2
|
+
import { openapi } from "../plugins/openapi";
|
|
3
|
+
|
|
4
|
+
// Create a BXO app with OpenAPI plugin
|
|
5
|
+
const app = new BXO()
|
|
6
|
+
.use(openapi({
|
|
7
|
+
path: "/docs",
|
|
8
|
+
jsonPath: "/openapi.json",
|
|
9
|
+
defaultTags: ["API"],
|
|
10
|
+
securitySchemes: {
|
|
11
|
+
bearerAuth: {
|
|
12
|
+
type: "http",
|
|
13
|
+
scheme: "bearer",
|
|
14
|
+
bearerFormat: "JWT",
|
|
15
|
+
description: "JWT token for authentication"
|
|
16
|
+
},
|
|
17
|
+
apiKeyAuth: {
|
|
18
|
+
type: "apiKey",
|
|
19
|
+
in: "header",
|
|
20
|
+
name: "X-API-Key",
|
|
21
|
+
description: "API key for authentication"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
globalSecurity: [
|
|
25
|
+
{ bearerAuth: [] },
|
|
26
|
+
{ apiKeyAuth: [] }
|
|
27
|
+
],
|
|
28
|
+
openapiConfig: {
|
|
29
|
+
info: {
|
|
30
|
+
title: "My API with Security",
|
|
31
|
+
version: "1.0.0",
|
|
32
|
+
description: "An example API with OpenAPI documentation, tags, and security"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}))
|
|
36
|
+
|
|
37
|
+
// Example routes with tags and security
|
|
38
|
+
app.get("/users", (ctx) => {
|
|
39
|
+
return { users: [] }
|
|
40
|
+
}, {
|
|
41
|
+
detail: {
|
|
42
|
+
tags: ["Users"],
|
|
43
|
+
summary: "Get all users",
|
|
44
|
+
description: "Retrieve a list of all users",
|
|
45
|
+
security: [{ bearerAuth: [] }]
|
|
46
|
+
}
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
app.get("/users/:id", (ctx) => {
|
|
50
|
+
const id = ctx.params.id
|
|
51
|
+
return { user: { id, name: "John Doe" } }
|
|
52
|
+
}, {
|
|
53
|
+
detail: {
|
|
54
|
+
tags: ["Users"],
|
|
55
|
+
summary: "Get user by ID",
|
|
56
|
+
description: "Retrieve a specific user by their ID",
|
|
57
|
+
params: {
|
|
58
|
+
id: z.string().describe("User ID")
|
|
59
|
+
},
|
|
60
|
+
security: [{ apiKeyAuth: [] }]
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
app.post("/users", (ctx) => {
|
|
65
|
+
const body = ctx.body
|
|
66
|
+
return { message: "User created", user: body }
|
|
67
|
+
}, {
|
|
68
|
+
body: z.object({
|
|
69
|
+
name: z.string(),
|
|
70
|
+
email: z.string().email()
|
|
71
|
+
}),
|
|
72
|
+
detail: {
|
|
73
|
+
tags: ["Users"],
|
|
74
|
+
summary: "Create a new user",
|
|
75
|
+
description: "Create a new user with the provided information",
|
|
76
|
+
security: [{ bearerAuth: [] }]
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
app.get("/products", (ctx) => {
|
|
81
|
+
return { products: [] }
|
|
82
|
+
}, {
|
|
83
|
+
detail: {
|
|
84
|
+
tags: ["Products"],
|
|
85
|
+
summary: "Get all products",
|
|
86
|
+
description: "Retrieve a list of all products"
|
|
87
|
+
}
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
app.get("/products/:id", (ctx) => {
|
|
91
|
+
const id = ctx.params.id
|
|
92
|
+
return { product: { id, name: "Sample Product" } }
|
|
93
|
+
}, {
|
|
94
|
+
detail: {
|
|
95
|
+
tags: ["Products"],
|
|
96
|
+
summary: "Get product by ID",
|
|
97
|
+
description: "Retrieve a specific product by its ID",
|
|
98
|
+
params: {
|
|
99
|
+
id: z.string().describe("Product ID")
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
// Admin routes with different security
|
|
105
|
+
app.get("/admin/users", (ctx) => {
|
|
106
|
+
return { adminUsers: [] }
|
|
107
|
+
}, {
|
|
108
|
+
detail: {
|
|
109
|
+
tags: ["Admin"],
|
|
110
|
+
summary: "Get all users (Admin)",
|
|
111
|
+
description: "Admin-only endpoint to retrieve all users",
|
|
112
|
+
security: [{ bearerAuth: [] }, { apiKeyAuth: [] }]
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
// Health check route (no security required)
|
|
117
|
+
app.get("/health", (ctx) => {
|
|
118
|
+
return { status: "ok", timestamp: new Date().toISOString() }
|
|
119
|
+
}, {
|
|
120
|
+
detail: {
|
|
121
|
+
tags: ["System"],
|
|
122
|
+
summary: "Health check",
|
|
123
|
+
description: "Check if the API is running"
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
// Start the server
|
|
128
|
+
app.listen(3000, () => {
|
|
129
|
+
console.log("Server running on http://localhost:3000")
|
|
130
|
+
console.log("OpenAPI docs available at http://localhost:3000/docs")
|
|
131
|
+
console.log("OpenAPI JSON available at http://localhost:3000/openapi.json")
|
|
132
|
+
})
|
package/package.json
CHANGED
package/plugins/openapi.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import BXO, { z } from "../src";
|
|
2
|
-
import { createDocument, type CreateDocumentOptions, type ZodOpenApiPathsObject } from "zod-openapi";
|
|
3
|
-
|
|
4
|
-
class OpenApiConfig {
|
|
2
|
+
import { createDocument, type CreateDocumentOptions, type ZodOpenApiPathsObject, type ZodOpenApiSecuritySchemeObject } from "zod-openapi";
|
|
5
3
|
|
|
4
|
+
interface SecurityScheme extends ZodOpenApiSecuritySchemeObject {
|
|
5
|
+
type: "http" | "apiKey" | "oauth2" | "openIdConnect";
|
|
6
|
+
scheme?: "bearer" | "basic" | "digest" | "apikey";
|
|
7
|
+
bearerFormat?: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
in?: "header" | "query" | "cookie";
|
|
6
11
|
}
|
|
7
12
|
|
|
8
13
|
interface OpenApiPluginConfig {
|
|
9
14
|
path: string;
|
|
10
15
|
jsonPath: string;
|
|
11
16
|
openapiConfig: CreateDocumentOptions;
|
|
17
|
+
defaultTags?: string[];
|
|
18
|
+
securitySchemes?: Record<string, SecurityScheme>;
|
|
19
|
+
globalSecurity?: Array<Record<string, string[]>>;
|
|
12
20
|
}
|
|
13
21
|
|
|
14
22
|
const createOpenApiPaths = (app: BXO, config?: OpenApiPluginConfig): ZodOpenApiPathsObject => {
|
|
@@ -30,6 +38,59 @@ const createOpenApiPaths = (app: BXO, config?: OpenApiPluginConfig): ZodOpenApiP
|
|
|
30
38
|
if (route.schema?.detail?.hidden) {
|
|
31
39
|
continue
|
|
32
40
|
}
|
|
41
|
+
|
|
42
|
+
// Extract tags from route metadata
|
|
43
|
+
const tags = route.schema?.detail?.tags ||
|
|
44
|
+
route.schema?.detail?.tag ||
|
|
45
|
+
config?.defaultTags ||
|
|
46
|
+
[]
|
|
47
|
+
|
|
48
|
+
// Extract security requirements from route metadata
|
|
49
|
+
const routeSecurity = route.schema?.detail?.security ||
|
|
50
|
+
route.schema?.detail?.auth ||
|
|
51
|
+
undefined
|
|
52
|
+
|
|
53
|
+
// Extract operation summary and description
|
|
54
|
+
const summary = route.schema?.detail?.summary ||
|
|
55
|
+
route.schema?.detail?.title ||
|
|
56
|
+
`${method.toUpperCase()} ${route.path}`
|
|
57
|
+
|
|
58
|
+
const description = route.schema?.detail?.description ||
|
|
59
|
+
route.schema?.detail?.docs ||
|
|
60
|
+
undefined
|
|
61
|
+
|
|
62
|
+
// Extract parameters from route path
|
|
63
|
+
const parameters = []
|
|
64
|
+
const pathParams = route.path.match(/:\w+/g)
|
|
65
|
+
if (pathParams) {
|
|
66
|
+
for (const param of pathParams) {
|
|
67
|
+
const paramName = param.slice(1) // Remove the colon
|
|
68
|
+
const paramSchema = route.schema?.detail?.params?.[paramName] || z.string()
|
|
69
|
+
parameters.push({
|
|
70
|
+
name: paramName,
|
|
71
|
+
in: "path",
|
|
72
|
+
required: true,
|
|
73
|
+
schema: paramSchema
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Add query parameters if defined
|
|
79
|
+
if (route.schema?.detail?.query) {
|
|
80
|
+
const querySchema = route.schema?.detail?.query
|
|
81
|
+
if (querySchema && typeof querySchema === 'object' && 'shape' in querySchema) {
|
|
82
|
+
const queryShape = (querySchema as any).shape
|
|
83
|
+
for (const [key, schema] of Object.entries(queryShape)) {
|
|
84
|
+
parameters.push({
|
|
85
|
+
name: key,
|
|
86
|
+
in: "query",
|
|
87
|
+
required: false, // Query params are typically optional
|
|
88
|
+
schema: schema as any
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
33
94
|
const response = Object.entries(route.schema?.response || {}).map(([status, schema]) => {
|
|
34
95
|
return ({
|
|
35
96
|
400: status === "400" && !route.schema?.response?.[status] ? {
|
|
@@ -51,9 +112,15 @@ const createOpenApiPaths = (app: BXO, config?: OpenApiPluginConfig): ZodOpenApiP
|
|
|
51
112
|
}
|
|
52
113
|
})
|
|
53
114
|
}).reduce((acc, curr) => ({ ...acc, ...curr }), {})
|
|
115
|
+
|
|
54
116
|
paths[openapiPath] = {
|
|
55
117
|
...paths[openapiPath],
|
|
56
118
|
[method]: {
|
|
119
|
+
tags: tags.length > 0 ? tags : undefined,
|
|
120
|
+
summary: summary,
|
|
121
|
+
description: description,
|
|
122
|
+
parameters: parameters.length > 0 ? parameters : undefined,
|
|
123
|
+
security: routeSecurity,
|
|
57
124
|
requestBody: {
|
|
58
125
|
content: {
|
|
59
126
|
[contentType]: {
|
|
@@ -78,11 +145,13 @@ const createOpenApiPaths = (app: BXO, config?: OpenApiPluginConfig): ZodOpenApiP
|
|
|
78
145
|
|
|
79
146
|
export function openapi(_config?: OpenApiPluginConfig) {
|
|
80
147
|
let config = _config
|
|
81
|
-
!config && (config = { path: "/docs", openapiConfig:
|
|
148
|
+
!config && (config = { path: "/docs", openapiConfig: {}, jsonPath: "/openapi.json" })
|
|
82
149
|
config.path = config.path || "/docs"
|
|
83
150
|
config.jsonPath = config.jsonPath || "/openapi.json"
|
|
84
151
|
config.openapiConfig = config.openapiConfig || {}
|
|
85
|
-
|
|
152
|
+
config.defaultTags = config.defaultTags || []
|
|
153
|
+
config.securitySchemes = config.securitySchemes || {}
|
|
154
|
+
config.globalSecurity = config.globalSecurity || []
|
|
86
155
|
|
|
87
156
|
const bxo = new BXO()
|
|
88
157
|
.get(config.jsonPath, (ctx, app) => {
|
|
@@ -93,6 +162,10 @@ export function openapi(_config?: OpenApiPluginConfig) {
|
|
|
93
162
|
version: "1.0.0"
|
|
94
163
|
},
|
|
95
164
|
paths: createOpenApiPaths(app, config),
|
|
165
|
+
components: {
|
|
166
|
+
securitySchemes: Object.keys(config.securitySchemes || {}).length > 0 ? config.securitySchemes : undefined
|
|
167
|
+
},
|
|
168
|
+
security: (config.globalSecurity || []).length > 0 ? config.globalSecurity : undefined,
|
|
96
169
|
...config.openapiConfig
|
|
97
170
|
})
|
|
98
171
|
return new Response(JSON.stringify(paths), {
|