@coherent.js/api 1.0.0-beta.2
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/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/api/errors.d.ts +92 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +161 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +61 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +41 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/middleware.d.ts +57 -0
- package/dist/api/middleware.d.ts.map +1 -0
- package/dist/api/middleware.js +244 -0
- package/dist/api/middleware.js.map +1 -0
- package/dist/api/openapi.d.ts +54 -0
- package/dist/api/openapi.d.ts.map +1 -0
- package/dist/api/openapi.js +144 -0
- package/dist/api/openapi.js.map +1 -0
- package/dist/api/router.d.ts +368 -0
- package/dist/api/router.d.ts.map +1 -0
- package/dist/api/router.js +1508 -0
- package/dist/api/router.js.map +1 -0
- package/dist/api/security.d.ts +64 -0
- package/dist/api/security.d.ts.map +1 -0
- package/dist/api/security.js +239 -0
- package/dist/api/security.js.map +1 -0
- package/dist/api/serialization.d.ts +86 -0
- package/dist/api/serialization.d.ts.map +1 -0
- package/dist/api/serialization.js +151 -0
- package/dist/api/serialization.js.map +1 -0
- package/dist/api/validation.d.ts +34 -0
- package/dist/api/validation.d.ts.map +1 -0
- package/dist/api/validation.js +172 -0
- package/dist/api/validation.js.map +1 -0
- package/dist/index.cjs +1776 -0
- package/dist/index.cjs.map +7 -0
- package/dist/index.js +1722 -0
- package/dist/index.js.map +7 -0
- package/package.json +46 -0
- package/types/index.d.ts +720 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware system for Coherent.js API framework
|
|
3
|
+
* @fileoverview Common middleware utilities for API routes
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Creates a custom API middleware with error handling
|
|
7
|
+
* @param {Function} handler - Middleware handler function
|
|
8
|
+
* @returns {Function} Middleware function that catches errors
|
|
9
|
+
*/
|
|
10
|
+
export function createApiMiddleware(handler) {
|
|
11
|
+
return (req, res, next) => {
|
|
12
|
+
try {
|
|
13
|
+
return handler(req, res, next);
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
// Pass errors to next middleware
|
|
17
|
+
next(error);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Authentication middleware
|
|
23
|
+
* @param {Function} verifyToken - Function to verify authentication token
|
|
24
|
+
* @returns {Function} Middleware function
|
|
25
|
+
*/
|
|
26
|
+
export function withAuth(verifyToken) {
|
|
27
|
+
return createApiMiddleware((req, res, next) => {
|
|
28
|
+
const authHeader = req.headers.authorization;
|
|
29
|
+
if (!authHeader) {
|
|
30
|
+
return res.status(401).json({
|
|
31
|
+
error: 'Unauthorized',
|
|
32
|
+
message: 'Missing authorization header'
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const token = authHeader.replace('Bearer ', '');
|
|
36
|
+
try {
|
|
37
|
+
const user = verifyToken(token);
|
|
38
|
+
req.user = user;
|
|
39
|
+
next();
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return res.status(401).json({
|
|
43
|
+
error: 'Unauthorized',
|
|
44
|
+
message: 'Invalid token'
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Authorization middleware
|
|
51
|
+
* @param {Function} checkPermission - Function to check user permissions
|
|
52
|
+
* @returns {Function} Middleware function
|
|
53
|
+
*/
|
|
54
|
+
export function withPermission(checkPermission) {
|
|
55
|
+
return createApiMiddleware((req, res, next) => {
|
|
56
|
+
if (!req.user) {
|
|
57
|
+
return res.status(401).json({
|
|
58
|
+
error: 'Unauthorized',
|
|
59
|
+
message: 'User not authenticated'
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
try {
|
|
63
|
+
const hasPermission = checkPermission(req.user, req);
|
|
64
|
+
if (!hasPermission) {
|
|
65
|
+
return res.status(403).json({
|
|
66
|
+
error: 'Forbidden',
|
|
67
|
+
message: 'Insufficient permissions'
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
next();
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return res.status(403).json({
|
|
74
|
+
error: 'Forbidden',
|
|
75
|
+
message: 'Permission check failed'
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Logging middleware
|
|
82
|
+
* @param {Object} options - Logging options
|
|
83
|
+
* @returns {Function} Middleware function
|
|
84
|
+
*/
|
|
85
|
+
export function withLogging(options = {}) {
|
|
86
|
+
const { logger = console, level = 'info' } = options;
|
|
87
|
+
return createApiMiddleware((req, res, next) => {
|
|
88
|
+
const startTime = Date.now();
|
|
89
|
+
// Log request
|
|
90
|
+
logger[level](`[${new Date().toISOString()}] ${req.method} ${req.url}`);
|
|
91
|
+
// Capture response finish to log completion
|
|
92
|
+
const originalSend = res.send;
|
|
93
|
+
res.send = function (body) {
|
|
94
|
+
const duration = Date.now() - startTime;
|
|
95
|
+
logger[level](`[${new Date().toISOString()}] ${req.method} ${req.url} ${res.statusCode} - ${duration}ms`);
|
|
96
|
+
return originalSend.call(this, body);
|
|
97
|
+
};
|
|
98
|
+
next();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* CORS middleware
|
|
103
|
+
* @param {Object} options - CORS options
|
|
104
|
+
* @returns {Function} Middleware function
|
|
105
|
+
*/
|
|
106
|
+
export function withCors(options = {}) {
|
|
107
|
+
const { origin = '*', methods = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], allowedHeaders = ['Content-Type', 'Authorization'], exposedHeaders = [], credentials = false, maxAge = 86400 } = options;
|
|
108
|
+
return createApiMiddleware((req, res, next) => {
|
|
109
|
+
// Set CORS headers
|
|
110
|
+
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
111
|
+
if (credentials) {
|
|
112
|
+
res.setHeader('Access-Control-Allow-Credentials', 'true');
|
|
113
|
+
}
|
|
114
|
+
if (req.method === 'OPTIONS') {
|
|
115
|
+
// Preflight request
|
|
116
|
+
res.setHeader('Access-Control-Allow-Methods', methods.join(', '));
|
|
117
|
+
res.setHeader('Access-Control-Allow-Headers', allowedHeaders.join(', '));
|
|
118
|
+
res.setHeader('Access-Control-Expose-Headers', exposedHeaders.join(', '));
|
|
119
|
+
res.setHeader('Access-Control-Max-Age', maxAge.toString());
|
|
120
|
+
res.status(204).send('');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
next();
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Rate limiting middleware
|
|
128
|
+
* @param {Object} options - Rate limiting options
|
|
129
|
+
* @returns {Function} Middleware function
|
|
130
|
+
*/
|
|
131
|
+
export function withRateLimit(options = {}) {
|
|
132
|
+
const { windowMs = 60000, // 1 minute
|
|
133
|
+
max = 100, // limit each IP to 100 requests per windowMs
|
|
134
|
+
message = 'Too many requests, please try again later', statusCode = 429 } = options;
|
|
135
|
+
// Store request counts per IP
|
|
136
|
+
const requestCounts = new Map();
|
|
137
|
+
// Cleanup old entries periodically (do not keep event loop alive)
|
|
138
|
+
const cleanupInterval = setInterval(() => {
|
|
139
|
+
const now = Date.now();
|
|
140
|
+
for (const [ip, record] of requestCounts.entries()) {
|
|
141
|
+
if (now - record.resetTime > windowMs) {
|
|
142
|
+
requestCounts.delete(ip);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}, windowMs);
|
|
146
|
+
if (typeof cleanupInterval.unref === 'function') {
|
|
147
|
+
cleanupInterval.unref();
|
|
148
|
+
}
|
|
149
|
+
return createApiMiddleware((req, res, next) => {
|
|
150
|
+
const ip = req.ip || req.connection.remoteAddress;
|
|
151
|
+
const now = Date.now();
|
|
152
|
+
if (!requestCounts.has(ip)) {
|
|
153
|
+
requestCounts.set(ip, {
|
|
154
|
+
count: 0,
|
|
155
|
+
resetTime: now + windowMs
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
const record = requestCounts.get(ip);
|
|
159
|
+
// Reset count if window has passed
|
|
160
|
+
if (now > record.resetTime) {
|
|
161
|
+
record.count = 0;
|
|
162
|
+
record.resetTime = now + windowMs;
|
|
163
|
+
}
|
|
164
|
+
// Increment count
|
|
165
|
+
record.count++;
|
|
166
|
+
// Check if limit exceeded
|
|
167
|
+
if (record.count > max) {
|
|
168
|
+
return res.status(statusCode).json({
|
|
169
|
+
error: 'Rate limit exceeded',
|
|
170
|
+
message
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Add rate limit info to response headers
|
|
174
|
+
res.setHeader('X-RateLimit-Limit', max);
|
|
175
|
+
res.setHeader('X-RateLimit-Remaining', Math.max(0, max - record.count));
|
|
176
|
+
res.setHeader('X-RateLimit-Reset', new Date(record.resetTime).toISOString());
|
|
177
|
+
next();
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Input sanitization middleware
|
|
182
|
+
* @param {Object} options - Sanitization options
|
|
183
|
+
* @returns {Function} Middleware function
|
|
184
|
+
*/
|
|
185
|
+
export function withSanitization(options = {}) {
|
|
186
|
+
const { sanitizeBody = true, sanitizeQuery = true, sanitizeParams = true } = options;
|
|
187
|
+
return createApiMiddleware((req, res, next) => {
|
|
188
|
+
if (sanitizeBody && req.body) {
|
|
189
|
+
req.body = sanitizeObject(req.body);
|
|
190
|
+
}
|
|
191
|
+
if (sanitizeQuery && req.query) {
|
|
192
|
+
req.query = sanitizeObject(req.query);
|
|
193
|
+
}
|
|
194
|
+
if (sanitizeParams && req.params) {
|
|
195
|
+
req.params = sanitizeObject(req.params);
|
|
196
|
+
}
|
|
197
|
+
next();
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Sanitize an object by escaping HTML entities
|
|
202
|
+
* @param {any} obj - Object to sanitize
|
|
203
|
+
* @returns {any} Sanitized object
|
|
204
|
+
*/
|
|
205
|
+
function sanitizeObject(obj) {
|
|
206
|
+
if (typeof obj === 'string') {
|
|
207
|
+
return sanitizeString(obj);
|
|
208
|
+
}
|
|
209
|
+
if (Array.isArray(obj)) {
|
|
210
|
+
return obj.map(sanitizeObject);
|
|
211
|
+
}
|
|
212
|
+
if (typeof obj === 'object' && obj !== null) {
|
|
213
|
+
const sanitized = {};
|
|
214
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
215
|
+
sanitized[key] = sanitizeObject(value);
|
|
216
|
+
}
|
|
217
|
+
return sanitized;
|
|
218
|
+
}
|
|
219
|
+
return obj;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Sanitize a string by escaping HTML entities
|
|
223
|
+
* @param {string} str - String to sanitize
|
|
224
|
+
* @returns {string} Sanitized string
|
|
225
|
+
*/
|
|
226
|
+
function sanitizeString(str) {
|
|
227
|
+
return str
|
|
228
|
+
.replace(/&/g, '&')
|
|
229
|
+
.replace(/</g, '<')
|
|
230
|
+
.replace(/>/g, '>')
|
|
231
|
+
.replace(/"/g, '"')
|
|
232
|
+
.replace(/'/g, ''');
|
|
233
|
+
}
|
|
234
|
+
// Export middleware utilities
|
|
235
|
+
export default {
|
|
236
|
+
createApiMiddleware,
|
|
237
|
+
withAuth,
|
|
238
|
+
withPermission,
|
|
239
|
+
withLogging,
|
|
240
|
+
withCors,
|
|
241
|
+
withRateLimit,
|
|
242
|
+
withSanitization
|
|
243
|
+
};
|
|
244
|
+
//# sourceMappingURL=middleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../../src/api/middleware.js"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI/Swagger integration for Coherent.js API framework
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create OpenAPI documentation middleware
|
|
6
|
+
* @param {Object} options - OpenAPI options
|
|
7
|
+
* @param {string} options.summary - Endpoint summary
|
|
8
|
+
* @param {string} options.description - Endpoint description
|
|
9
|
+
* @param {Object} options.responses - Response schemas
|
|
10
|
+
* @param {Object} options.requestBody - Request body schema
|
|
11
|
+
* @param {Object} options.parameters - Path/query parameters
|
|
12
|
+
* @returns {Function} Middleware function
|
|
13
|
+
*/
|
|
14
|
+
export function withOpenApi(options?: {
|
|
15
|
+
summary: string;
|
|
16
|
+
description: string;
|
|
17
|
+
responses: Object;
|
|
18
|
+
requestBody: Object;
|
|
19
|
+
parameters: Object;
|
|
20
|
+
}): Function;
|
|
21
|
+
/**
|
|
22
|
+
* Generate OpenAPI specification from registered routes
|
|
23
|
+
* @param {Object} appInfo - Application information
|
|
24
|
+
* @param {string} appInfo.title - Application title
|
|
25
|
+
* @param {string} appInfo.version - Application version
|
|
26
|
+
* @param {string} appInfo.description - Application description
|
|
27
|
+
* @param {Array} routes - Registered routes
|
|
28
|
+
* @returns {Object} OpenAPI specification
|
|
29
|
+
*/
|
|
30
|
+
export function generateOpenApiSpec(appInfo?: {
|
|
31
|
+
title: string;
|
|
32
|
+
version: string;
|
|
33
|
+
description: string;
|
|
34
|
+
}, routes?: any[]): Object;
|
|
35
|
+
/**
|
|
36
|
+
* Create OpenAPI documentation endpoint
|
|
37
|
+
* @param {Object} appInfo - Application information
|
|
38
|
+
* @param {Array} routes - Registered routes
|
|
39
|
+
* @returns {Function} Handler function
|
|
40
|
+
*/
|
|
41
|
+
export function createOpenApiHandler(appInfo?: Object, routes?: any[]): Function;
|
|
42
|
+
/**
|
|
43
|
+
* Create Swagger UI endpoint
|
|
44
|
+
* @returns {Function} Handler function
|
|
45
|
+
*/
|
|
46
|
+
export function createSwaggerUIHandler(): Function;
|
|
47
|
+
declare namespace _default {
|
|
48
|
+
export { withOpenApi };
|
|
49
|
+
export { generateOpenApiSpec };
|
|
50
|
+
export { createOpenApiHandler };
|
|
51
|
+
export { createSwaggerUIHandler };
|
|
52
|
+
}
|
|
53
|
+
export default _default;
|
|
54
|
+
//# sourceMappingURL=openapi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.d.ts","sourceRoot":"","sources":["../../../../src/api/openapi.js"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;;;;;;;GASG;AACH,sCAPG;IAAwB,OAAO,EAAvB,MAAM;IACU,WAAW,EAA3B,MAAM;IACU,SAAS,EAAzB,MAAM;IACU,WAAW,EAA3B,MAAM;IACU,UAAU,EAA1B,MAAM;CACd,YAoBF;AAED;;;;;;;;GAQG;AACH,8CANG;IAAwB,KAAK,EAArB,MAAM;IACU,OAAO,EAAvB,MAAM;IACU,WAAW,EAA3B,MAAM;CACd,mBACU,MAAM,CA+ClB;AAYD;;;;;GAKG;AACH,+CAJW,MAAM,4BAUhB;AAED;;;GAGG;AACH,mDA6BC"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAPI/Swagger integration for Coherent.js API framework
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create OpenAPI documentation middleware
|
|
6
|
+
* @param {Object} options - OpenAPI options
|
|
7
|
+
* @param {string} options.summary - Endpoint summary
|
|
8
|
+
* @param {string} options.description - Endpoint description
|
|
9
|
+
* @param {Object} options.responses - Response schemas
|
|
10
|
+
* @param {Object} options.requestBody - Request body schema
|
|
11
|
+
* @param {Object} options.parameters - Path/query parameters
|
|
12
|
+
* @returns {Function} Middleware function
|
|
13
|
+
*/
|
|
14
|
+
export function withOpenApi(options = {}) {
|
|
15
|
+
return (req, res, next) => {
|
|
16
|
+
// Add OpenAPI metadata to request for documentation generation
|
|
17
|
+
if (!req.openapi) {
|
|
18
|
+
req.openapi = {};
|
|
19
|
+
}
|
|
20
|
+
// Store endpoint metadata
|
|
21
|
+
req.openapi[req.method + req.url] = {
|
|
22
|
+
summary: options.summary || '',
|
|
23
|
+
description: options.description || '',
|
|
24
|
+
responses: options.responses || {},
|
|
25
|
+
requestBody: options.requestBody,
|
|
26
|
+
parameters: options.parameters || []
|
|
27
|
+
};
|
|
28
|
+
next();
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Generate OpenAPI specification from registered routes
|
|
33
|
+
* @param {Object} appInfo - Application information
|
|
34
|
+
* @param {string} appInfo.title - Application title
|
|
35
|
+
* @param {string} appInfo.version - Application version
|
|
36
|
+
* @param {string} appInfo.description - Application description
|
|
37
|
+
* @param {Array} routes - Registered routes
|
|
38
|
+
* @returns {Object} OpenAPI specification
|
|
39
|
+
*/
|
|
40
|
+
export function generateOpenApiSpec(appInfo = {}, routes = []) {
|
|
41
|
+
const spec = {
|
|
42
|
+
openapi: '3.0.0',
|
|
43
|
+
info: {
|
|
44
|
+
title: appInfo.title || 'Coherent.js API',
|
|
45
|
+
version: appInfo.version || '1.0.0',
|
|
46
|
+
description: appInfo.description || 'API documentation for Coherent.js application'
|
|
47
|
+
},
|
|
48
|
+
paths: {}
|
|
49
|
+
};
|
|
50
|
+
// Process each route
|
|
51
|
+
routes.forEach(route => {
|
|
52
|
+
const path = normalizePath(route.path);
|
|
53
|
+
const method = route.method.toLowerCase();
|
|
54
|
+
if (!spec.paths[path]) {
|
|
55
|
+
spec.paths[path] = {};
|
|
56
|
+
}
|
|
57
|
+
// Add operation
|
|
58
|
+
spec.paths[path][method] = {
|
|
59
|
+
summary: route.openapi?.summary || '',
|
|
60
|
+
description: route.openapi?.description || '',
|
|
61
|
+
parameters: route.openapi?.parameters || [],
|
|
62
|
+
responses: route.openapi?.responses || {
|
|
63
|
+
'200': {
|
|
64
|
+
description: 'Successful response'
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
// Add request body if specified
|
|
69
|
+
if (route.openapi?.requestBody) {
|
|
70
|
+
spec.paths[path][method].requestBody = {
|
|
71
|
+
content: {
|
|
72
|
+
'application/json': {
|
|
73
|
+
schema: route.openapi.requestBody
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
return spec;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Normalize path for OpenAPI
|
|
83
|
+
* @param {string} path - Route path
|
|
84
|
+
* @returns {string} Normalized path
|
|
85
|
+
*/
|
|
86
|
+
function normalizePath(path) {
|
|
87
|
+
// Convert Express-style params (:id) to OpenAPI style ({id})
|
|
88
|
+
return path.replace(/:(\w+)/g, '{$1}');
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Create OpenAPI documentation endpoint
|
|
92
|
+
* @param {Object} appInfo - Application information
|
|
93
|
+
* @param {Array} routes - Registered routes
|
|
94
|
+
* @returns {Function} Handler function
|
|
95
|
+
*/
|
|
96
|
+
export function createOpenApiHandler(appInfo = {}, routes = []) {
|
|
97
|
+
return (req, res) => {
|
|
98
|
+
const spec = generateOpenApiSpec(appInfo, routes);
|
|
99
|
+
res.setHeader('Content-Type', 'application/json');
|
|
100
|
+
return spec;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Create Swagger UI endpoint
|
|
105
|
+
* @returns {Function} Handler function
|
|
106
|
+
*/
|
|
107
|
+
export function createSwaggerUIHandler() {
|
|
108
|
+
return (req, res) => {
|
|
109
|
+
const html = `
|
|
110
|
+
<!DOCTYPE html>
|
|
111
|
+
<html lang="en">
|
|
112
|
+
<head>
|
|
113
|
+
<meta charset="UTF-8">
|
|
114
|
+
<title>Coherent.js API Documentation</title>
|
|
115
|
+
<link rel="stylesheet" type="text/css" href="https://unpkg.com/swagger-ui-dist@4/swagger-ui-bundle.css" />
|
|
116
|
+
</head>
|
|
117
|
+
<body>
|
|
118
|
+
<div id="swagger-ui"></div>
|
|
119
|
+
<script src="https://unpkg.com/swagger-ui-dist@4/swagger-ui-bundle.js"></script>
|
|
120
|
+
<script>
|
|
121
|
+
SwaggerUIBundle({
|
|
122
|
+
url: '/api/docs/json',
|
|
123
|
+
dom_id: '#swagger-ui',
|
|
124
|
+
presets: [
|
|
125
|
+
SwaggerUIBundle.presets.apis,
|
|
126
|
+
SwaggerUIBundle.presets.standalone
|
|
127
|
+
]
|
|
128
|
+
});
|
|
129
|
+
</script>
|
|
130
|
+
</body>
|
|
131
|
+
</html>
|
|
132
|
+
`;
|
|
133
|
+
res.setHeader('Content-Type', 'text/html');
|
|
134
|
+
return html;
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
// Export OpenAPI utilities
|
|
138
|
+
export default {
|
|
139
|
+
withOpenApi,
|
|
140
|
+
generateOpenApiSpec,
|
|
141
|
+
createOpenApiHandler,
|
|
142
|
+
createSwaggerUIHandler
|
|
143
|
+
};
|
|
144
|
+
//# sourceMappingURL=openapi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openapi.js","sourceRoot":"","sources":["../../../../src/api/openapi.js"],"names":[],"mappings":"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"}
|