create-fluxstack 1.0.0 → 1.0.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/create-fluxstack.ts +32 -17
- package/package-template.json +51 -0
- package/package.json +2 -1
- package/.env +0 -30
- package/LICENSE +0 -21
- package/app/client/README.md +0 -69
- package/app/client/frontend-only.ts +0 -12
- package/app/client/index.html +0 -13
- package/app/client/public/vite.svg +0 -1
- package/app/client/src/App.css +0 -883
- package/app/client/src/App.tsx +0 -669
- package/app/client/src/assets/react.svg +0 -1
- package/app/client/src/components/TestPage.tsx +0 -453
- package/app/client/src/index.css +0 -51
- package/app/client/src/lib/eden-api.ts +0 -110
- package/app/client/src/main.tsx +0 -10
- package/app/client/src/vite-env.d.ts +0 -1
- package/app/client/tsconfig.app.json +0 -43
- package/app/client/tsconfig.json +0 -7
- package/app/client/tsconfig.node.json +0 -25
- package/app/server/app.ts +0 -10
- package/app/server/backend-only.ts +0 -15
- package/app/server/controllers/users.controller.ts +0 -69
- package/app/server/index.ts +0 -104
- package/app/server/routes/index.ts +0 -25
- package/app/server/routes/users.routes.ts +0 -121
- package/app/server/types/index.ts +0 -1
- package/app/shared/types/index.ts +0 -18
- package/bun.lock +0 -1053
- package/core/__tests__/integration.test.ts +0 -227
- package/core/build/index.ts +0 -186
- package/core/cli/command-registry.ts +0 -334
- package/core/cli/index.ts +0 -394
- package/core/cli/plugin-discovery.ts +0 -200
- package/core/client/standalone.ts +0 -57
- package/core/config/__tests__/config-loader.test.ts +0 -591
- package/core/config/__tests__/config-merger.test.ts +0 -657
- package/core/config/__tests__/env-converter.test.ts +0 -372
- package/core/config/__tests__/env-processor.test.ts +0 -431
- package/core/config/__tests__/env.test.ts +0 -452
- package/core/config/__tests__/integration.test.ts +0 -418
- package/core/config/__tests__/loader.test.ts +0 -331
- package/core/config/__tests__/schema.test.ts +0 -129
- package/core/config/__tests__/validator.test.ts +0 -318
- package/core/config/env-dynamic.ts +0 -326
- package/core/config/env.ts +0 -597
- package/core/config/index.ts +0 -317
- package/core/config/loader.ts +0 -546
- package/core/config/runtime-config.ts +0 -322
- package/core/config/schema.ts +0 -694
- package/core/config/validator.ts +0 -540
- package/core/framework/__tests__/server.test.ts +0 -233
- package/core/framework/client.ts +0 -132
- package/core/framework/index.ts +0 -8
- package/core/framework/server.ts +0 -501
- package/core/framework/types.ts +0 -63
- package/core/plugins/__tests__/built-in.test.ts.disabled +0 -366
- package/core/plugins/__tests__/manager.test.ts +0 -398
- package/core/plugins/__tests__/monitoring.test.ts +0 -401
- package/core/plugins/__tests__/registry.test.ts +0 -335
- package/core/plugins/built-in/index.ts +0 -142
- package/core/plugins/built-in/logger/index.ts +0 -180
- package/core/plugins/built-in/monitoring/README.md +0 -193
- package/core/plugins/built-in/monitoring/index.ts +0 -912
- package/core/plugins/built-in/static/index.ts +0 -289
- package/core/plugins/built-in/swagger/index.ts +0 -229
- package/core/plugins/built-in/vite/index.ts +0 -316
- package/core/plugins/config.ts +0 -348
- package/core/plugins/discovery.ts +0 -350
- package/core/plugins/executor.ts +0 -351
- package/core/plugins/index.ts +0 -195
- package/core/plugins/manager.ts +0 -583
- package/core/plugins/registry.ts +0 -424
- package/core/plugins/types.ts +0 -254
- package/core/server/framework.ts +0 -123
- package/core/server/index.ts +0 -8
- package/core/server/plugins/database.ts +0 -182
- package/core/server/plugins/logger.ts +0 -47
- package/core/server/plugins/swagger.ts +0 -34
- package/core/server/standalone.ts +0 -91
- package/core/templates/create-project.ts +0 -455
- package/core/types/api.ts +0 -169
- package/core/types/build.ts +0 -174
- package/core/types/config.ts +0 -68
- package/core/types/index.ts +0 -127
- package/core/types/plugin.ts +0 -94
- package/core/utils/__tests__/errors.test.ts +0 -139
- package/core/utils/__tests__/helpers.test.ts +0 -297
- package/core/utils/__tests__/logger.test.ts +0 -141
- package/core/utils/env-runtime-v2.ts +0 -232
- package/core/utils/env-runtime.ts +0 -252
- package/core/utils/errors/codes.ts +0 -115
- package/core/utils/errors/handlers.ts +0 -63
- package/core/utils/errors/index.ts +0 -81
- package/core/utils/helpers.ts +0 -180
- package/core/utils/index.ts +0 -18
- package/core/utils/logger/index.ts +0 -161
- package/core/utils/logger.ts +0 -106
- package/core/utils/monitoring/index.ts +0 -212
- package/tsconfig.json +0 -51
- package/vite.config.ts +0 -42
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import { join, extname } from "path"
|
|
2
|
-
import { existsSync, statSync } from "fs"
|
|
3
|
-
import type { Plugin, PluginContext } from "../../types"
|
|
4
|
-
|
|
5
|
-
export const staticPlugin: Plugin = {
|
|
6
|
-
name: "static",
|
|
7
|
-
version: "1.0.0",
|
|
8
|
-
description: "Enhanced static file serving plugin for FluxStack with caching and compression",
|
|
9
|
-
author: "FluxStack Team",
|
|
10
|
-
priority: "low", // Should run after other plugins
|
|
11
|
-
category: "core",
|
|
12
|
-
tags: ["static", "files", "spa"],
|
|
13
|
-
dependencies: [], // No hard dependencies, but works with vite plugin
|
|
14
|
-
|
|
15
|
-
configSchema: {
|
|
16
|
-
type: "object",
|
|
17
|
-
properties: {
|
|
18
|
-
enabled: {
|
|
19
|
-
type: "boolean",
|
|
20
|
-
description: "Enable static file serving"
|
|
21
|
-
},
|
|
22
|
-
publicDir: {
|
|
23
|
-
type: "string",
|
|
24
|
-
description: "Public directory for static files"
|
|
25
|
-
},
|
|
26
|
-
distDir: {
|
|
27
|
-
type: "string",
|
|
28
|
-
description: "Distribution directory for built files"
|
|
29
|
-
},
|
|
30
|
-
indexFile: {
|
|
31
|
-
type: "string",
|
|
32
|
-
description: "Index file for SPA routing"
|
|
33
|
-
},
|
|
34
|
-
cacheControl: {
|
|
35
|
-
type: "object",
|
|
36
|
-
properties: {
|
|
37
|
-
enabled: { type: "boolean" },
|
|
38
|
-
maxAge: { type: "number" },
|
|
39
|
-
immutable: { type: "boolean" }
|
|
40
|
-
},
|
|
41
|
-
description: "Cache control settings"
|
|
42
|
-
},
|
|
43
|
-
compression: {
|
|
44
|
-
type: "object",
|
|
45
|
-
properties: {
|
|
46
|
-
enabled: { type: "boolean" },
|
|
47
|
-
types: {
|
|
48
|
-
type: "array",
|
|
49
|
-
items: { type: "string" }
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
|
-
description: "Compression settings"
|
|
53
|
-
},
|
|
54
|
-
spa: {
|
|
55
|
-
type: "object",
|
|
56
|
-
properties: {
|
|
57
|
-
enabled: { type: "boolean" },
|
|
58
|
-
fallback: { type: "string" }
|
|
59
|
-
},
|
|
60
|
-
description: "Single Page Application settings"
|
|
61
|
-
},
|
|
62
|
-
excludePaths: {
|
|
63
|
-
type: "array",
|
|
64
|
-
items: { type: "string" },
|
|
65
|
-
description: "Paths to exclude from static serving"
|
|
66
|
-
}
|
|
67
|
-
},
|
|
68
|
-
additionalProperties: false
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
defaultConfig: {
|
|
72
|
-
enabled: true,
|
|
73
|
-
publicDir: "public",
|
|
74
|
-
distDir: "dist/client",
|
|
75
|
-
indexFile: "index.html",
|
|
76
|
-
cacheControl: {
|
|
77
|
-
enabled: true,
|
|
78
|
-
maxAge: 31536000, // 1 year for assets
|
|
79
|
-
immutable: true
|
|
80
|
-
},
|
|
81
|
-
compression: {
|
|
82
|
-
enabled: true,
|
|
83
|
-
types: [".js", ".css", ".html", ".json", ".svg"]
|
|
84
|
-
},
|
|
85
|
-
spa: {
|
|
86
|
-
enabled: true,
|
|
87
|
-
fallback: "index.html"
|
|
88
|
-
},
|
|
89
|
-
excludePaths: []
|
|
90
|
-
},
|
|
91
|
-
|
|
92
|
-
setup: async (context: PluginContext) => {
|
|
93
|
-
const config = getPluginConfig(context)
|
|
94
|
-
|
|
95
|
-
if (!config.enabled) {
|
|
96
|
-
context.logger.info('Static files plugin disabled by configuration')
|
|
97
|
-
return
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
context.logger.info("Enhanced static files plugin activated", {
|
|
101
|
-
publicDir: config.publicDir,
|
|
102
|
-
distDir: config.distDir,
|
|
103
|
-
spa: config.spa.enabled,
|
|
104
|
-
compression: config.compression.enabled
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
// Setup static file handling in Elysia
|
|
108
|
-
context.app.get("/*", async ({ request, set }: { request: Request, set: any }) => {
|
|
109
|
-
const url = new URL(request.url)
|
|
110
|
-
|
|
111
|
-
// Skip API routes
|
|
112
|
-
if (url.pathname.startsWith(context.config.server.apiPrefix)) {
|
|
113
|
-
return
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// Skip excluded paths
|
|
117
|
-
if (config.excludePaths.some((path: string) => url.pathname.startsWith(path))) {
|
|
118
|
-
return
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
try {
|
|
122
|
-
// Note: Vite proxy is now handled by the Vite plugin via onBeforeRoute hook
|
|
123
|
-
// This plugin only handles static files serving in production or fallback
|
|
124
|
-
|
|
125
|
-
// Serve static files
|
|
126
|
-
return await serveStaticFile(url.pathname, config, context, set)
|
|
127
|
-
|
|
128
|
-
} catch (error) {
|
|
129
|
-
context.logger.error("Error serving static file", {
|
|
130
|
-
path: url.pathname,
|
|
131
|
-
error: error instanceof Error ? error.message : String(error)
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
set.status = 500
|
|
135
|
-
return "Internal Server Error"
|
|
136
|
-
}
|
|
137
|
-
})
|
|
138
|
-
},
|
|
139
|
-
|
|
140
|
-
onServerStart: async (context: PluginContext) => {
|
|
141
|
-
const config = getPluginConfig(context)
|
|
142
|
-
|
|
143
|
-
if (config.enabled) {
|
|
144
|
-
const mode = context.utils.isDevelopment() ? 'development' : 'production'
|
|
145
|
-
context.logger.info(`Static files plugin ready in ${mode} mode`, {
|
|
146
|
-
publicDir: config.publicDir,
|
|
147
|
-
distDir: config.distDir,
|
|
148
|
-
spa: config.spa.enabled
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// Helper function to get plugin config
|
|
155
|
-
function getPluginConfig(context: PluginContext) {
|
|
156
|
-
const pluginConfig = context.config.plugins.config?.static || {}
|
|
157
|
-
return { ...staticPlugin.defaultConfig, ...pluginConfig }
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Serve static file
|
|
161
|
-
async function serveStaticFile(
|
|
162
|
-
pathname: string,
|
|
163
|
-
config: any,
|
|
164
|
-
context: PluginContext,
|
|
165
|
-
set: any
|
|
166
|
-
): Promise<any> {
|
|
167
|
-
const isDev = context.utils.isDevelopment()
|
|
168
|
-
|
|
169
|
-
// Determine base directory using path discovery (no hardcoded detection)
|
|
170
|
-
let baseDir: string
|
|
171
|
-
|
|
172
|
-
if (isDev && existsSync(config.publicDir)) {
|
|
173
|
-
// Development: use public directory
|
|
174
|
-
baseDir = config.publicDir
|
|
175
|
-
} else {
|
|
176
|
-
// Production: try paths in order of preference
|
|
177
|
-
if (existsSync('client')) {
|
|
178
|
-
// Found client/ in current directory (running from dist/)
|
|
179
|
-
baseDir = 'client'
|
|
180
|
-
} else if (existsSync('dist/client')) {
|
|
181
|
-
// Found dist/client/ (running from project root)
|
|
182
|
-
baseDir = 'dist/client'
|
|
183
|
-
} else {
|
|
184
|
-
// Fallback to configured path
|
|
185
|
-
baseDir = config.distDir
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
if (!existsSync(baseDir)) {
|
|
190
|
-
context.logger.warn(`Static directory not found: ${baseDir}`)
|
|
191
|
-
set.status = 404
|
|
192
|
-
return "Not Found"
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// Clean pathname
|
|
196
|
-
const cleanPath = pathname === '/' ? `/${config.indexFile}` : pathname
|
|
197
|
-
const filePath = join(process.cwd(), baseDir, cleanPath)
|
|
198
|
-
|
|
199
|
-
// Security check - prevent directory traversal
|
|
200
|
-
const resolvedPath = join(process.cwd(), baseDir)
|
|
201
|
-
if (!filePath.startsWith(resolvedPath)) {
|
|
202
|
-
set.status = 403
|
|
203
|
-
return "Forbidden"
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// Check if file exists
|
|
207
|
-
if (!existsSync(filePath)) {
|
|
208
|
-
// For SPA, serve index.html for non-file routes
|
|
209
|
-
if (config.spa.enabled && !pathname.includes('.')) {
|
|
210
|
-
const indexPath = join(process.cwd(), baseDir, config.spa.fallback)
|
|
211
|
-
if (existsSync(indexPath)) {
|
|
212
|
-
return serveFile(indexPath, config, set, context)
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
set.status = 404
|
|
217
|
-
return "Not Found"
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Check if it's a directory
|
|
221
|
-
const stats = statSync(filePath)
|
|
222
|
-
if (stats.isDirectory()) {
|
|
223
|
-
const indexPath = join(filePath, config.indexFile)
|
|
224
|
-
if (existsSync(indexPath)) {
|
|
225
|
-
return serveFile(indexPath, config, set, context)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
set.status = 404
|
|
229
|
-
return "Not Found"
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return serveFile(filePath, config, set, context)
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Serve individual file
|
|
236
|
-
function serveFile(filePath: string, config: any, set: any, context: PluginContext) {
|
|
237
|
-
const ext = extname(filePath)
|
|
238
|
-
const file = Bun.file(filePath)
|
|
239
|
-
|
|
240
|
-
// Set content type
|
|
241
|
-
const mimeTypes: Record<string, string> = {
|
|
242
|
-
'.html': 'text/html',
|
|
243
|
-
'.css': 'text/css',
|
|
244
|
-
'.js': 'application/javascript',
|
|
245
|
-
'.json': 'application/json',
|
|
246
|
-
'.png': 'image/png',
|
|
247
|
-
'.jpg': 'image/jpeg',
|
|
248
|
-
'.jpeg': 'image/jpeg',
|
|
249
|
-
'.gif': 'image/gif',
|
|
250
|
-
'.svg': 'image/svg+xml',
|
|
251
|
-
'.ico': 'image/x-icon',
|
|
252
|
-
'.woff': 'font/woff',
|
|
253
|
-
'.woff2': 'font/woff2',
|
|
254
|
-
'.ttf': 'font/ttf',
|
|
255
|
-
'.eot': 'application/vnd.ms-fontobject'
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const contentType = mimeTypes[ext] || 'application/octet-stream'
|
|
259
|
-
set.headers['Content-Type'] = contentType
|
|
260
|
-
|
|
261
|
-
// Set cache headers
|
|
262
|
-
if (config.cacheControl.enabled) {
|
|
263
|
-
if (ext === '.html') {
|
|
264
|
-
// Don't cache HTML files aggressively
|
|
265
|
-
set.headers['Cache-Control'] = 'no-cache'
|
|
266
|
-
} else {
|
|
267
|
-
// Cache assets aggressively
|
|
268
|
-
const maxAge = config.cacheControl.maxAge
|
|
269
|
-
const cacheControl = config.cacheControl.immutable
|
|
270
|
-
? `public, max-age=${maxAge}, immutable`
|
|
271
|
-
: `public, max-age=${maxAge}`
|
|
272
|
-
set.headers['Cache-Control'] = cacheControl
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Add compression hint if enabled
|
|
277
|
-
if (config.compression.enabled && config.compression.types.includes(ext)) {
|
|
278
|
-
set.headers['Vary'] = 'Accept-Encoding'
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
context.logger.debug(`Serving static file: ${filePath}`, {
|
|
282
|
-
contentType,
|
|
283
|
-
size: file.size
|
|
284
|
-
})
|
|
285
|
-
|
|
286
|
-
return file
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
export default staticPlugin
|
|
@@ -1,229 +0,0 @@
|
|
|
1
|
-
import { swagger } from '@elysiajs/swagger'
|
|
2
|
-
import type { Plugin, PluginContext } from '../../types'
|
|
3
|
-
|
|
4
|
-
export const swaggerPlugin: Plugin = {
|
|
5
|
-
name: 'swagger',
|
|
6
|
-
version: '1.0.0',
|
|
7
|
-
description: 'Enhanced Swagger documentation plugin for FluxStack with customizable options',
|
|
8
|
-
author: 'FluxStack Team',
|
|
9
|
-
priority: 'normal',
|
|
10
|
-
category: 'documentation',
|
|
11
|
-
tags: ['swagger', 'documentation', 'api'],
|
|
12
|
-
dependencies: [], // No dependencies
|
|
13
|
-
|
|
14
|
-
configSchema: {
|
|
15
|
-
type: 'object',
|
|
16
|
-
properties: {
|
|
17
|
-
enabled: {
|
|
18
|
-
type: 'boolean',
|
|
19
|
-
description: 'Enable Swagger documentation'
|
|
20
|
-
},
|
|
21
|
-
path: {
|
|
22
|
-
type: 'string',
|
|
23
|
-
description: 'Swagger UI path'
|
|
24
|
-
},
|
|
25
|
-
title: {
|
|
26
|
-
type: 'string',
|
|
27
|
-
description: 'API documentation title'
|
|
28
|
-
},
|
|
29
|
-
description: {
|
|
30
|
-
type: 'string',
|
|
31
|
-
description: 'API documentation description'
|
|
32
|
-
},
|
|
33
|
-
version: {
|
|
34
|
-
type: 'string',
|
|
35
|
-
description: 'API version'
|
|
36
|
-
},
|
|
37
|
-
tags: {
|
|
38
|
-
type: 'array',
|
|
39
|
-
items: {
|
|
40
|
-
type: 'object',
|
|
41
|
-
properties: {
|
|
42
|
-
name: { type: 'string' },
|
|
43
|
-
description: { type: 'string' }
|
|
44
|
-
},
|
|
45
|
-
required: ['name']
|
|
46
|
-
},
|
|
47
|
-
description: 'API tags for grouping endpoints'
|
|
48
|
-
},
|
|
49
|
-
servers: {
|
|
50
|
-
type: 'array',
|
|
51
|
-
items: {
|
|
52
|
-
type: 'object',
|
|
53
|
-
properties: {
|
|
54
|
-
url: { type: 'string' },
|
|
55
|
-
description: { type: 'string' }
|
|
56
|
-
},
|
|
57
|
-
required: ['url']
|
|
58
|
-
},
|
|
59
|
-
description: 'API servers'
|
|
60
|
-
},
|
|
61
|
-
excludePaths: {
|
|
62
|
-
type: 'array',
|
|
63
|
-
items: { type: 'string' },
|
|
64
|
-
description: 'Paths to exclude from documentation'
|
|
65
|
-
},
|
|
66
|
-
securitySchemes: {
|
|
67
|
-
type: 'object',
|
|
68
|
-
description: 'Security schemes definition'
|
|
69
|
-
},
|
|
70
|
-
globalSecurity: {
|
|
71
|
-
type: 'array',
|
|
72
|
-
items: {
|
|
73
|
-
type: 'object'
|
|
74
|
-
},
|
|
75
|
-
description: 'Global security requirements'
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
additionalProperties: false
|
|
79
|
-
},
|
|
80
|
-
|
|
81
|
-
defaultConfig: {
|
|
82
|
-
enabled: true,
|
|
83
|
-
path: '/swagger',
|
|
84
|
-
title: 'FluxStack API',
|
|
85
|
-
description: 'Modern full-stack TypeScript framework with type-safe API endpoints',
|
|
86
|
-
version: '1.0.0',
|
|
87
|
-
tags: [
|
|
88
|
-
{
|
|
89
|
-
name: 'Health',
|
|
90
|
-
description: 'Health check endpoints'
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
name: 'API',
|
|
94
|
-
description: 'API endpoints'
|
|
95
|
-
}
|
|
96
|
-
],
|
|
97
|
-
servers: [],
|
|
98
|
-
excludePaths: [],
|
|
99
|
-
securitySchemes: {},
|
|
100
|
-
globalSecurity: []
|
|
101
|
-
},
|
|
102
|
-
|
|
103
|
-
setup: async (context: PluginContext) => {
|
|
104
|
-
const config = getPluginConfig(context)
|
|
105
|
-
|
|
106
|
-
if (!config.enabled) {
|
|
107
|
-
context.logger.info('Swagger plugin disabled by configuration')
|
|
108
|
-
return
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
try {
|
|
112
|
-
// Build servers list
|
|
113
|
-
const servers = config.servers.length > 0 ? config.servers : [
|
|
114
|
-
{
|
|
115
|
-
url: `http://${context.config.server.host}:${context.config.server.port}`,
|
|
116
|
-
description: 'Development server'
|
|
117
|
-
}
|
|
118
|
-
]
|
|
119
|
-
|
|
120
|
-
// Add production server if in production
|
|
121
|
-
if (context.utils.isProduction()) {
|
|
122
|
-
servers.push({
|
|
123
|
-
url: 'https://api.example.com', // This would be configured
|
|
124
|
-
description: 'Production server'
|
|
125
|
-
})
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const swaggerConfig = {
|
|
129
|
-
path: config.path,
|
|
130
|
-
documentation: {
|
|
131
|
-
info: {
|
|
132
|
-
title: config.title || context.config.app?.name || 'FluxStack API',
|
|
133
|
-
version: config.version || context.config.app?.version || '1.0.0',
|
|
134
|
-
description: config.description || context.config.app?.description || 'Modern full-stack TypeScript framework with type-safe API endpoints'
|
|
135
|
-
},
|
|
136
|
-
tags: config.tags,
|
|
137
|
-
servers,
|
|
138
|
-
|
|
139
|
-
// Add security schemes if defined
|
|
140
|
-
...(Object.keys(config.securitySchemes).length > 0 && {
|
|
141
|
-
components: {
|
|
142
|
-
securitySchemes: config.securitySchemes
|
|
143
|
-
}
|
|
144
|
-
}),
|
|
145
|
-
|
|
146
|
-
// Add global security if defined
|
|
147
|
-
...(config.globalSecurity.length > 0 && {
|
|
148
|
-
security: config.globalSecurity
|
|
149
|
-
})
|
|
150
|
-
},
|
|
151
|
-
exclude: config.excludePaths,
|
|
152
|
-
swaggerOptions: {
|
|
153
|
-
persistAuthorization: true,
|
|
154
|
-
displayRequestDuration: true,
|
|
155
|
-
filter: true,
|
|
156
|
-
showExtensions: true,
|
|
157
|
-
tryItOutEnabled: true
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
context.app.use(swagger(swaggerConfig))
|
|
162
|
-
|
|
163
|
-
context.logger.info(`Swagger documentation enabled at ${config.path}`, {
|
|
164
|
-
title: swaggerConfig.documentation.info.title,
|
|
165
|
-
version: swaggerConfig.documentation.info.version,
|
|
166
|
-
servers: servers.length
|
|
167
|
-
})
|
|
168
|
-
} catch (error) {
|
|
169
|
-
context.logger.error('Failed to setup Swagger plugin', { error })
|
|
170
|
-
throw error
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
|
|
174
|
-
onServerStart: async (context: PluginContext) => {
|
|
175
|
-
const config = getPluginConfig(context)
|
|
176
|
-
|
|
177
|
-
if (config.enabled) {
|
|
178
|
-
const swaggerUrl = `http://${context.config.server.host}:${context.config.server.port}${config.path}`
|
|
179
|
-
context.logger.info(`Swagger documentation available at: ${swaggerUrl}`)
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// Helper function to get plugin config from context
|
|
185
|
-
function getPluginConfig(context: PluginContext) {
|
|
186
|
-
// In a real implementation, this would get the config from the plugin context
|
|
187
|
-
// For now, merge default config with any provided config
|
|
188
|
-
const pluginConfig = context.config.plugins.config?.swagger || {}
|
|
189
|
-
return { ...swaggerPlugin.defaultConfig, ...pluginConfig }
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Example usage for security configuration:
|
|
193
|
-
//
|
|
194
|
-
// To enable security in your FluxStack app, configure like this:
|
|
195
|
-
//
|
|
196
|
-
// plugins: {
|
|
197
|
-
// config: {
|
|
198
|
-
// swagger: {
|
|
199
|
-
// securitySchemes: {
|
|
200
|
-
// bearerAuth: {
|
|
201
|
-
// type: 'http',
|
|
202
|
-
// scheme: 'bearer',
|
|
203
|
-
// bearerFormat: 'JWT'
|
|
204
|
-
// },
|
|
205
|
-
// apiKeyAuth: {
|
|
206
|
-
// type: 'apiKey',
|
|
207
|
-
// in: 'header',
|
|
208
|
-
// name: 'X-API-Key'
|
|
209
|
-
// }
|
|
210
|
-
// },
|
|
211
|
-
// globalSecurity: [
|
|
212
|
-
// { bearerAuth: [] } // Apply JWT auth globally
|
|
213
|
-
// ]
|
|
214
|
-
// }
|
|
215
|
-
// }
|
|
216
|
-
// }
|
|
217
|
-
//
|
|
218
|
-
// Then in your routes, you can override per endpoint:
|
|
219
|
-
// app.get('/public', handler, {
|
|
220
|
-
// detail: { security: [] } // No auth required
|
|
221
|
-
// })
|
|
222
|
-
//
|
|
223
|
-
// app.get('/private', handler, {
|
|
224
|
-
// detail: {
|
|
225
|
-
// security: [{ apiKeyAuth: [] }] // API key required
|
|
226
|
-
// }
|
|
227
|
-
// })
|
|
228
|
-
|
|
229
|
-
export default swaggerPlugin
|