create-fluxstack 1.8.1 â 1.8.3
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/.env.example +19 -0
- package/README.md +6 -3
- package/app/client/SIMPLIFICATION.md +140 -0
- package/app/client/frontend-only.ts +1 -1
- package/app/client/src/App.tsx +148 -283
- package/app/client/src/index.css +5 -20
- package/app/client/src/lib/eden-api.ts +53 -220
- package/app/client/src/main.tsx +2 -3
- package/app/server/controllers/users.controller.ts +57 -31
- package/app/server/index.ts +5 -2
- package/app/server/live/register-components.ts +18 -7
- package/app/server/routes/env-test.ts +53 -2
- package/app/server/routes/index.ts +1 -8
- package/app/server/routes/users.routes.ts +192 -91
- package/config/fluxstack.config.ts +2 -2
- package/config/plugins.config.ts +22 -1
- package/core/build/flux-plugins-generator.ts +5 -5
- package/core/build/live-components-generator.ts +15 -12
- package/core/cli/command-registry.ts +4 -14
- package/core/cli/commands/plugin-deps.ts +8 -8
- package/core/cli/generators/component.ts +3 -3
- package/core/cli/generators/controller.ts +4 -4
- package/core/cli/generators/index.ts +8 -8
- package/core/cli/generators/interactive.ts +4 -4
- package/core/cli/generators/plugin.ts +3 -3
- package/core/cli/generators/prompts.ts +1 -1
- package/core/cli/generators/route.ts +27 -11
- package/core/cli/generators/service.ts +5 -5
- package/core/cli/generators/template-engine.ts +1 -1
- package/core/cli/generators/types.ts +1 -1
- package/core/cli/index.ts +158 -193
- package/core/cli/plugin-discovery.ts +3 -3
- package/core/client/hooks/index.ts +2 -2
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +1 -1
- package/core/client/hooks/useChunkedUpload.ts +1 -1
- package/core/client/hooks/useHybridLiveComponent.ts +1 -1
- package/core/client/hooks/useWebSocket.ts +1 -1
- package/core/config/env.ts +1 -1
- package/core/config/runtime-config.ts +5 -5
- package/core/config/schema.ts +9 -0
- package/core/framework/server.ts +30 -15
- package/core/framework/types.ts +2 -2
- package/core/live/ComponentRegistry.ts +1 -1
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +65 -161
- package/core/plugins/built-in/static/index.ts +18 -47
- package/core/plugins/built-in/swagger/index.ts +301 -231
- package/core/plugins/built-in/vite/index.ts +74 -109
- package/core/plugins/config.ts +2 -2
- package/core/plugins/dependency-manager.ts +2 -2
- package/core/plugins/discovery.ts +1 -1
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/manager.ts +19 -4
- package/core/plugins/module-resolver.ts +1 -1
- package/core/plugins/registry.ts +3 -3
- package/core/plugins/types.ts +147 -5
- package/core/server/framework.ts +2 -2
- package/core/server/live/ComponentRegistry.ts +9 -26
- package/core/server/live/FileUploadManager.ts +1 -1
- package/core/server/live/auto-generated-components.ts +26 -0
- package/core/server/live/websocket-plugin.ts +211 -19
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +4 -4
- package/core/server/plugins/database.ts +1 -2
- package/core/server/plugins/static-files-plugin.ts +259 -231
- package/core/server/plugins/swagger.ts +1 -1
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +4 -4
- package/core/server/standalone.ts +16 -1
- package/core/testing/index.ts +1 -1
- package/core/testing/setup.ts +1 -1
- package/core/utils/logger/startup-banner.ts +7 -33
- package/core/utils/version.ts +6 -6
- package/create-fluxstack.ts +68 -25
- package/package.json +2 -2
- package/plugins/crypto-auth/index.ts +52 -47
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
- package/vitest.config.ts +11 -2
- package/app/client/src/App.css +0 -883
- package/app/client/src/components/ErrorBoundary.tsx +0 -107
- package/app/client/src/components/ErrorDisplay.css +0 -365
- package/app/client/src/components/ErrorDisplay.tsx +0 -258
- package/app/client/src/components/FluxStackConfig.tsx +0 -1321
- package/app/client/src/components/HybridLiveCounter.tsx +0 -140
- package/app/client/src/components/LiveClock.tsx +0 -286
- package/app/client/src/components/MainLayout.tsx +0 -388
- package/app/client/src/components/SidebarNavigation.tsx +0 -391
- package/app/client/src/components/StateDemo.tsx +0 -178
- package/app/client/src/components/SystemMonitor.tsx +0 -1044
- package/app/client/src/components/UserProfile.tsx +0 -809
- package/app/client/src/hooks/useAuth.ts +0 -39
- package/app/client/src/hooks/useNotifications.ts +0 -56
- package/app/client/src/lib/errors.ts +0 -340
- package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
- package/app/client/src/lib/index.ts +0 -45
- package/app/client/src/pages/ApiDocs.tsx +0 -182
- package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
- package/app/client/src/pages/Demo.tsx +0 -174
- package/app/client/src/pages/HybridLive.tsx +0 -263
- package/app/client/src/pages/Overview.tsx +0 -155
- package/app/client/src/store/README.md +0 -43
- package/app/client/src/store/index.ts +0 -16
- package/app/client/src/store/slices/uiSlice.ts +0 -151
- package/app/client/src/store/slices/userSlice.ts +0 -161
- package/app/client/src/test/README.md +0 -257
- package/app/client/src/test/setup.ts +0 -70
- package/app/client/src/test/types.ts +0 -12
- package/app/server/live/CounterComponent.ts +0 -191
- package/app/server/live/FluxStackConfig.ts +0 -534
- package/app/server/live/SidebarNavigation.ts +0 -157
- package/app/server/live/SystemMonitor.ts +0 -595
- package/app/server/live/SystemMonitorIntegration.ts +0 -151
- package/app/server/live/UserProfileComponent.ts +0 -141
- package/app/server/middleware/auth.ts +0 -136
- package/app/server/middleware/errorHandling.ts +0 -252
- package/app/server/middleware/index.ts +0 -10
- package/app/server/middleware/rateLimit.ts +0 -193
- package/app/server/middleware/requestLogging.ts +0 -215
- package/app/server/middleware/validation.ts +0 -270
- package/app/server/routes/config.ts +0 -145
- package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
- package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
- package/app/server/routes/exemplo-posts.routes.ts +0 -161
- package/app/server/routes/upload.ts +0 -92
- package/app/server/services/NotificationService.ts +0 -302
- package/app/server/services/UserService.ts +0 -222
- package/app/server/services/index.ts +0 -46
- package/app/server/types/index.ts +0 -1
|
@@ -1,232 +1,260 @@
|
|
|
1
|
-
// đĨ FluxStack Static Files Plugin - Serve Public Files
|
|
2
|
-
|
|
3
|
-
import { existsSync, statSync } from 'fs'
|
|
4
|
-
import { join, extname, resolve } from 'path'
|
|
5
|
-
import type { FluxStack, PluginContext } from '
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
//
|
|
69
|
-
'.
|
|
70
|
-
'.
|
|
71
|
-
'.
|
|
72
|
-
'.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
'.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
set.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
return
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
//
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
1
|
+
// đĨ FluxStack Static Files Plugin - Serve Public Files
|
|
2
|
+
|
|
3
|
+
import { existsSync, statSync } from 'fs'
|
|
4
|
+
import { join, extname, resolve } from 'path'
|
|
5
|
+
import type { FluxStack, PluginContext, Plugin } from '../../plugins/types'
|
|
6
|
+
import { t } from 'elysia'
|
|
7
|
+
|
|
8
|
+
// Response schema for static files info endpoint
|
|
9
|
+
const StaticFilesInfoSchema = t.Object({
|
|
10
|
+
success: t.Boolean(),
|
|
11
|
+
config: t.Object({
|
|
12
|
+
publicDir: t.String(),
|
|
13
|
+
uploadsDir: t.String(),
|
|
14
|
+
enablePublic: t.Boolean(),
|
|
15
|
+
enableUploads: t.Boolean(),
|
|
16
|
+
cacheMaxAge: t.Number()
|
|
17
|
+
}),
|
|
18
|
+
paths: t.Object({
|
|
19
|
+
publicPath: t.String(),
|
|
20
|
+
uploadsPath: t.String(),
|
|
21
|
+
publicUrl: t.String(),
|
|
22
|
+
uploadsUrl: t.String()
|
|
23
|
+
}),
|
|
24
|
+
timestamp: t.String()
|
|
25
|
+
}, {
|
|
26
|
+
description: 'Static files configuration and paths information'
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
export interface StaticFilesConfig {
|
|
30
|
+
publicDir?: string // Default: 'public'
|
|
31
|
+
uploadsDir?: string // Default: 'uploads'
|
|
32
|
+
cacheMaxAge?: number // Default: 1 year in seconds
|
|
33
|
+
enableUploads?: boolean // Default: true
|
|
34
|
+
enablePublic?: boolean // Default: true
|
|
35
|
+
publicRoute?: string // Default: '/public' (can be '/static' in dev)
|
|
36
|
+
uploadsRoute?: string // Default: '/uploads'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const staticFilesPlugin: Plugin = {
|
|
40
|
+
name: 'static-files',
|
|
41
|
+
description: 'Serve static files and uploads with proper caching and security',
|
|
42
|
+
author: 'FluxStack Team',
|
|
43
|
+
priority: 'normal',
|
|
44
|
+
category: 'core',
|
|
45
|
+
tags: ['static', 'files', 'uploads', 'public'],
|
|
46
|
+
|
|
47
|
+
setup: async (context: PluginContext) => {
|
|
48
|
+
context.logger.debug('đ Setting up Static Files plugin...')
|
|
49
|
+
|
|
50
|
+
const config: StaticFilesConfig = {
|
|
51
|
+
publicDir: 'public',
|
|
52
|
+
uploadsDir: 'uploads',
|
|
53
|
+
cacheMaxAge: 31536000, // 1 year
|
|
54
|
+
enableUploads: true,
|
|
55
|
+
enablePublic: true,
|
|
56
|
+
publicRoute: '/api/static', // Use /api/static in dev to avoid Vite conflicts
|
|
57
|
+
uploadsRoute: '/api/uploads',
|
|
58
|
+
...context.config.staticFiles
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const projectRoot = process.cwd()
|
|
62
|
+
const publicPath = resolve(projectRoot, config.publicDir!)
|
|
63
|
+
const uploadsPath = resolve(projectRoot, config.uploadsDir!)
|
|
64
|
+
|
|
65
|
+
// MIME types mapping
|
|
66
|
+
const getMimeType = (extension: string): string => {
|
|
67
|
+
const mimeTypes: Record<string, string> = {
|
|
68
|
+
// Images
|
|
69
|
+
'.jpg': 'image/jpeg',
|
|
70
|
+
'.jpeg': 'image/jpeg',
|
|
71
|
+
'.png': 'image/png',
|
|
72
|
+
'.gif': 'image/gif',
|
|
73
|
+
'.webp': 'image/webp',
|
|
74
|
+
'.svg': 'image/svg+xml',
|
|
75
|
+
'.ico': 'image/x-icon',
|
|
76
|
+
|
|
77
|
+
// Documents
|
|
78
|
+
'.pdf': 'application/pdf',
|
|
79
|
+
'.txt': 'text/plain',
|
|
80
|
+
'.json': 'application/json',
|
|
81
|
+
'.xml': 'application/xml',
|
|
82
|
+
|
|
83
|
+
// Web assets
|
|
84
|
+
'.css': 'text/css',
|
|
85
|
+
'.js': 'application/javascript',
|
|
86
|
+
'.html': 'text/html',
|
|
87
|
+
'.htm': 'text/html',
|
|
88
|
+
|
|
89
|
+
// Fonts
|
|
90
|
+
'.woff': 'font/woff',
|
|
91
|
+
'.woff2': 'font/woff2',
|
|
92
|
+
'.ttf': 'font/ttf',
|
|
93
|
+
'.otf': 'font/otf',
|
|
94
|
+
|
|
95
|
+
// Audio/Video
|
|
96
|
+
'.mp3': 'audio/mpeg',
|
|
97
|
+
'.mp4': 'video/mp4',
|
|
98
|
+
'.webm': 'video/webm',
|
|
99
|
+
'.ogg': 'audio/ogg'
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return mimeTypes[extension.toLowerCase()] || 'application/octet-stream'
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Security check for path traversal
|
|
106
|
+
const isPathSafe = (filePath: string, basePath: string): boolean => {
|
|
107
|
+
const resolvedPath = resolve(basePath, filePath)
|
|
108
|
+
return resolvedPath.startsWith(basePath)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Generic file serving function
|
|
112
|
+
const serveFile = async (filePath: string, set: any) => {
|
|
113
|
+
try {
|
|
114
|
+
if (!existsSync(filePath)) {
|
|
115
|
+
set.status = 404
|
|
116
|
+
return {
|
|
117
|
+
error: 'File not found',
|
|
118
|
+
path: filePath.replace(projectRoot, ''),
|
|
119
|
+
timestamp: new Date().toISOString()
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const stats = statSync(filePath)
|
|
124
|
+
if (!stats.isFile()) {
|
|
125
|
+
set.status = 404
|
|
126
|
+
return { error: 'Not a file' }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Set appropriate headers
|
|
130
|
+
const extension = extname(filePath).toLowerCase()
|
|
131
|
+
const mimeType = getMimeType(extension)
|
|
132
|
+
|
|
133
|
+
set.headers['content-type'] = mimeType
|
|
134
|
+
set.headers['content-length'] = stats.size.toString()
|
|
135
|
+
set.headers['last-modified'] = stats.mtime.toUTCString()
|
|
136
|
+
set.headers['cache-control'] = `public, max-age=${config.cacheMaxAge}`
|
|
137
|
+
set.headers['etag'] = `"${stats.mtime.getTime()}-${stats.size}"`
|
|
138
|
+
|
|
139
|
+
// Security headers for images
|
|
140
|
+
if (mimeType.startsWith('image/')) {
|
|
141
|
+
set.headers['x-content-type-options'] = 'nosniff'
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
context.logger.debug(`đ Serving file: ${filePath.replace(projectRoot, '')}`, {
|
|
145
|
+
size: stats.size,
|
|
146
|
+
mimeType,
|
|
147
|
+
lastModified: stats.mtime
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
return Bun.file(filePath)
|
|
151
|
+
|
|
152
|
+
} catch (error: any) {
|
|
153
|
+
context.logger.error('â File serving error:', error.message)
|
|
154
|
+
set.status = 500
|
|
155
|
+
return { error: 'Failed to serve file' }
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Add static file routes
|
|
160
|
+
if (config.enablePublic) {
|
|
161
|
+
const publicRoutePattern = `${config.publicRoute}/*`
|
|
162
|
+
context.app.get(publicRoutePattern, ({ params, set }) => {
|
|
163
|
+
const filePath = params['*'] || ''
|
|
164
|
+
|
|
165
|
+
if (!isPathSafe(filePath, publicPath)) {
|
|
166
|
+
set.status = 400
|
|
167
|
+
return { error: 'Invalid file path' }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const fullPath = join(publicPath, filePath)
|
|
171
|
+
return serveFile(fullPath, set)
|
|
172
|
+
})
|
|
173
|
+
|
|
174
|
+
context.logger.debug(`đ Public files route enabled: ${publicRoutePattern} â ${config.publicDir}`)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (config.enableUploads) {
|
|
178
|
+
const uploadsRoutePattern = `${config.uploadsRoute}/*`
|
|
179
|
+
context.app.get(uploadsRoutePattern, ({ params, set }) => {
|
|
180
|
+
const filePath = params['*'] || ''
|
|
181
|
+
|
|
182
|
+
if (!isPathSafe(filePath, uploadsPath)) {
|
|
183
|
+
set.status = 400
|
|
184
|
+
return { error: 'Invalid file path' }
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const fullPath = join(uploadsPath, filePath)
|
|
188
|
+
return serveFile(fullPath, set)
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
context.logger.debug(`đ Uploads route enabled: ${uploadsRoutePattern} â ${config.uploadsDir}`)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Static files info endpoint
|
|
195
|
+
context.app.get('/api/static/info', () => {
|
|
196
|
+
return {
|
|
197
|
+
success: true,
|
|
198
|
+
config: {
|
|
199
|
+
publicDir: config.publicDir,
|
|
200
|
+
uploadsDir: config.uploadsDir,
|
|
201
|
+
enablePublic: config.enablePublic,
|
|
202
|
+
enableUploads: config.enableUploads,
|
|
203
|
+
cacheMaxAge: config.cacheMaxAge
|
|
204
|
+
},
|
|
205
|
+
paths: {
|
|
206
|
+
publicPath,
|
|
207
|
+
uploadsPath,
|
|
208
|
+
publicUrl: config.publicRoute,
|
|
209
|
+
uploadsUrl: config.uploadsRoute
|
|
210
|
+
},
|
|
211
|
+
timestamp: new Date().toISOString()
|
|
212
|
+
}
|
|
213
|
+
}, {
|
|
214
|
+
detail: {
|
|
215
|
+
summary: 'Static Files Configuration',
|
|
216
|
+
description: 'Returns configuration and paths for static files and uploads serving',
|
|
217
|
+
tags: ['Static Files', 'Configuration']
|
|
218
|
+
},
|
|
219
|
+
response: StaticFilesInfoSchema
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
// Create directories if they don't exist
|
|
223
|
+
const { mkdir } = await import('fs/promises')
|
|
224
|
+
|
|
225
|
+
if (config.enablePublic && !existsSync(publicPath)) {
|
|
226
|
+
await mkdir(publicPath, { recursive: true })
|
|
227
|
+
context.logger.debug(`đ Created public directory: ${publicPath}`)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (config.enableUploads && !existsSync(uploadsPath)) {
|
|
231
|
+
await mkdir(uploadsPath, { recursive: true })
|
|
232
|
+
await mkdir(join(uploadsPath, 'avatars'), { recursive: true })
|
|
233
|
+
context.logger.debug(`đ Created uploads directory: ${uploadsPath}`)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
context.logger.debug('đ Static Files plugin setup complete', {
|
|
237
|
+
publicEnabled: config.enablePublic,
|
|
238
|
+
uploadsEnabled: config.enableUploads,
|
|
239
|
+
publicPath: config.enablePublic ? publicPath : 'disabled',
|
|
240
|
+
uploadsPath: config.enableUploads ? uploadsPath : 'disabled'
|
|
241
|
+
})
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
onServerStart: async (context: PluginContext) => {
|
|
245
|
+
const config = {
|
|
246
|
+
enablePublic: true,
|
|
247
|
+
enableUploads: true,
|
|
248
|
+
publicRoute: '/api/static',
|
|
249
|
+
uploadsRoute: '/api/uploads',
|
|
250
|
+
...context.config.staticFiles
|
|
251
|
+
}
|
|
252
|
+
context.logger.debug('đ Static Files plugin ready', {
|
|
253
|
+
routes: [
|
|
254
|
+
config.enablePublic ? `${config.publicRoute}/*` : null,
|
|
255
|
+
config.enableUploads ? `${config.uploadsRoute}/*` : null,
|
|
256
|
+
'/api/static/info'
|
|
257
|
+
].filter(Boolean)
|
|
258
|
+
})
|
|
259
|
+
}
|
|
232
260
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Provides service registration, resolution, and lifecycle management
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { Logger } from '
|
|
8
|
+
import type { Logger } from '@/core/utils/logger/index'
|
|
9
9
|
|
|
10
10
|
export interface ServiceDefinition {
|
|
11
11
|
factory: (container: ServiceContainer) => any
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* FluxStack service infrastructure exports
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
export { BaseService } from './BaseService
|
|
7
|
-
export { ServiceContainer } from './ServiceContainer
|
|
8
|
-
export type { ServiceContext, ServiceContainer as IServiceContainer } from './BaseService
|
|
9
|
-
export type { ServiceDefinition } from './ServiceContainer
|
|
6
|
+
export { BaseService } from './BaseService'
|
|
7
|
+
export { ServiceContainer } from './ServiceContainer'
|
|
8
|
+
export type { ServiceContext, ServiceContainer as IServiceContainer } from './BaseService'
|
|
9
|
+
export type { ServiceDefinition } from './ServiceContainer'
|
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
import { FluxStackFramework } from "./index"
|
|
3
3
|
import type { Plugin, PluginContext } from "../types"
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Helper to safely parse request.url which might be relative or absolute
|
|
7
|
+
*/
|
|
8
|
+
function parseRequestURL(request: Request): URL {
|
|
9
|
+
try {
|
|
10
|
+
// Try parsing as absolute URL first
|
|
11
|
+
return new URL(request.url)
|
|
12
|
+
} catch {
|
|
13
|
+
// If relative, use host from headers or default to localhost
|
|
14
|
+
const host = request.headers.get('host') || 'localhost'
|
|
15
|
+
const protocol = request.headers.get('x-forwarded-proto') || 'http'
|
|
16
|
+
return new URL(request.url, `${protocol}://${host}`)
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
export const createStandaloneServer = (userConfig: any = {}) => {
|
|
6
21
|
const app = new FluxStackFramework({
|
|
7
22
|
server: {
|
|
@@ -29,7 +44,7 @@ export const createStandaloneServer = (userConfig: any = {}) => {
|
|
|
29
44
|
context.app.onRequest(({ request }: { request: Request }) => {
|
|
30
45
|
// Log mais limpo para backend standalone
|
|
31
46
|
const timestamp = new Date().toLocaleTimeString()
|
|
32
|
-
const path =
|
|
47
|
+
const path = parseRequestURL(request).pathname
|
|
33
48
|
console.log(`[${timestamp}] ${request.method} ${path}`)
|
|
34
49
|
})
|
|
35
50
|
}
|
package/core/testing/index.ts
CHANGED
package/core/testing/setup.ts
CHANGED
|
@@ -33,43 +33,17 @@ export function displayStartupBanner(info: StartupInfo): void {
|
|
|
33
33
|
pluginCount = 0,
|
|
34
34
|
vitePort,
|
|
35
35
|
viteEmbedded = false,
|
|
36
|
-
swaggerPath
|
|
37
36
|
} = info
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
console.log(` ${chalk.gray('â')} API: http://localhost:${port}${apiPrefix}`)
|
|
45
|
-
console.log(` ${chalk.gray('â')} Health: http://localhost:${port}${apiPrefix}/health`)
|
|
46
|
-
|
|
47
|
-
// Frontend info (only if Vite is running standalone, NOT embedded)
|
|
48
|
-
if (vitePort && !viteEmbedded) {
|
|
49
|
-
console.log('')
|
|
50
|
-
console.log(chalk.bold('âī¸ Frontend'))
|
|
51
|
-
console.log(` ${chalk.gray('â')} http://localhost:${vitePort}`)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Swagger docs (if enabled)
|
|
55
|
-
if (swaggerPath) {
|
|
56
|
-
console.log('')
|
|
57
|
-
console.log(chalk.bold('đ Documentation'))
|
|
58
|
-
console.log(` ${chalk.gray('â')} Swagger: http://localhost:${port}${swaggerPath}`)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Environment and plugins
|
|
62
|
-
console.log('')
|
|
63
|
-
console.log(chalk.bold('âšī¸ Info'))
|
|
64
|
-
console.log(` ${chalk.gray('â')} Environment: ${chalk.green(environment)}`)
|
|
65
|
-
console.log(` ${chalk.gray('â')} Plugins: ${chalk.yellow(pluginCount)}`)
|
|
66
|
-
|
|
67
|
-
// Show Vite embedded status when applicable
|
|
68
|
-
if (viteEmbedded && vitePort) {
|
|
69
|
-
console.log(` ${chalk.gray('â')} Vite: ${chalk.magenta('embedded')} ${chalk.gray(`(port ${vitePort})`)}`)
|
|
38
|
+
// Display plugins in compact format
|
|
39
|
+
const plugins = (global as any).__fluxstackPlugins || []
|
|
40
|
+
if (plugins.length > 0) {
|
|
41
|
+
const pluginList = plugins.map((p: any) => `${p.name} (${p.details})`).join(', ')
|
|
42
|
+
console.log(`Plugins (${plugins.length}): ${pluginList}\n`)
|
|
70
43
|
}
|
|
71
44
|
|
|
72
|
-
|
|
45
|
+
// Simple ready message
|
|
46
|
+
console.log(chalk.green('Server ready!') + chalk.gray(` Environment: ${environment}${viteEmbedded ? ' | Vite: embedded' : ''}\n`))
|
|
73
47
|
}
|
|
74
48
|
|
|
75
49
|
/**
|