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.
Files changed (101) hide show
  1. package/create-fluxstack.ts +32 -17
  2. package/package-template.json +51 -0
  3. package/package.json +2 -1
  4. package/.env +0 -30
  5. package/LICENSE +0 -21
  6. package/app/client/README.md +0 -69
  7. package/app/client/frontend-only.ts +0 -12
  8. package/app/client/index.html +0 -13
  9. package/app/client/public/vite.svg +0 -1
  10. package/app/client/src/App.css +0 -883
  11. package/app/client/src/App.tsx +0 -669
  12. package/app/client/src/assets/react.svg +0 -1
  13. package/app/client/src/components/TestPage.tsx +0 -453
  14. package/app/client/src/index.css +0 -51
  15. package/app/client/src/lib/eden-api.ts +0 -110
  16. package/app/client/src/main.tsx +0 -10
  17. package/app/client/src/vite-env.d.ts +0 -1
  18. package/app/client/tsconfig.app.json +0 -43
  19. package/app/client/tsconfig.json +0 -7
  20. package/app/client/tsconfig.node.json +0 -25
  21. package/app/server/app.ts +0 -10
  22. package/app/server/backend-only.ts +0 -15
  23. package/app/server/controllers/users.controller.ts +0 -69
  24. package/app/server/index.ts +0 -104
  25. package/app/server/routes/index.ts +0 -25
  26. package/app/server/routes/users.routes.ts +0 -121
  27. package/app/server/types/index.ts +0 -1
  28. package/app/shared/types/index.ts +0 -18
  29. package/bun.lock +0 -1053
  30. package/core/__tests__/integration.test.ts +0 -227
  31. package/core/build/index.ts +0 -186
  32. package/core/cli/command-registry.ts +0 -334
  33. package/core/cli/index.ts +0 -394
  34. package/core/cli/plugin-discovery.ts +0 -200
  35. package/core/client/standalone.ts +0 -57
  36. package/core/config/__tests__/config-loader.test.ts +0 -591
  37. package/core/config/__tests__/config-merger.test.ts +0 -657
  38. package/core/config/__tests__/env-converter.test.ts +0 -372
  39. package/core/config/__tests__/env-processor.test.ts +0 -431
  40. package/core/config/__tests__/env.test.ts +0 -452
  41. package/core/config/__tests__/integration.test.ts +0 -418
  42. package/core/config/__tests__/loader.test.ts +0 -331
  43. package/core/config/__tests__/schema.test.ts +0 -129
  44. package/core/config/__tests__/validator.test.ts +0 -318
  45. package/core/config/env-dynamic.ts +0 -326
  46. package/core/config/env.ts +0 -597
  47. package/core/config/index.ts +0 -317
  48. package/core/config/loader.ts +0 -546
  49. package/core/config/runtime-config.ts +0 -322
  50. package/core/config/schema.ts +0 -694
  51. package/core/config/validator.ts +0 -540
  52. package/core/framework/__tests__/server.test.ts +0 -233
  53. package/core/framework/client.ts +0 -132
  54. package/core/framework/index.ts +0 -8
  55. package/core/framework/server.ts +0 -501
  56. package/core/framework/types.ts +0 -63
  57. package/core/plugins/__tests__/built-in.test.ts.disabled +0 -366
  58. package/core/plugins/__tests__/manager.test.ts +0 -398
  59. package/core/plugins/__tests__/monitoring.test.ts +0 -401
  60. package/core/plugins/__tests__/registry.test.ts +0 -335
  61. package/core/plugins/built-in/index.ts +0 -142
  62. package/core/plugins/built-in/logger/index.ts +0 -180
  63. package/core/plugins/built-in/monitoring/README.md +0 -193
  64. package/core/plugins/built-in/monitoring/index.ts +0 -912
  65. package/core/plugins/built-in/static/index.ts +0 -289
  66. package/core/plugins/built-in/swagger/index.ts +0 -229
  67. package/core/plugins/built-in/vite/index.ts +0 -316
  68. package/core/plugins/config.ts +0 -348
  69. package/core/plugins/discovery.ts +0 -350
  70. package/core/plugins/executor.ts +0 -351
  71. package/core/plugins/index.ts +0 -195
  72. package/core/plugins/manager.ts +0 -583
  73. package/core/plugins/registry.ts +0 -424
  74. package/core/plugins/types.ts +0 -254
  75. package/core/server/framework.ts +0 -123
  76. package/core/server/index.ts +0 -8
  77. package/core/server/plugins/database.ts +0 -182
  78. package/core/server/plugins/logger.ts +0 -47
  79. package/core/server/plugins/swagger.ts +0 -34
  80. package/core/server/standalone.ts +0 -91
  81. package/core/templates/create-project.ts +0 -455
  82. package/core/types/api.ts +0 -169
  83. package/core/types/build.ts +0 -174
  84. package/core/types/config.ts +0 -68
  85. package/core/types/index.ts +0 -127
  86. package/core/types/plugin.ts +0 -94
  87. package/core/utils/__tests__/errors.test.ts +0 -139
  88. package/core/utils/__tests__/helpers.test.ts +0 -297
  89. package/core/utils/__tests__/logger.test.ts +0 -141
  90. package/core/utils/env-runtime-v2.ts +0 -232
  91. package/core/utils/env-runtime.ts +0 -252
  92. package/core/utils/errors/codes.ts +0 -115
  93. package/core/utils/errors/handlers.ts +0 -63
  94. package/core/utils/errors/index.ts +0 -81
  95. package/core/utils/helpers.ts +0 -180
  96. package/core/utils/index.ts +0 -18
  97. package/core/utils/logger/index.ts +0 -161
  98. package/core/utils/logger.ts +0 -106
  99. package/core/utils/monitoring/index.ts +0 -212
  100. package/tsconfig.json +0 -51
  101. 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