create-fluxstack 1.0.22 → 1.4.0

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 (82) hide show
  1. package/app/server/backend-only.ts +5 -5
  2. package/app/server/index.ts +63 -54
  3. package/app/server/live/FluxStackConfig.ts +43 -39
  4. package/app/server/live/SystemMonitorIntegration.ts +2 -2
  5. package/app/server/live/register-components.ts +6 -26
  6. package/app/server/middleware/errorHandling.ts +6 -4
  7. package/app/server/routes/config.ts +145 -0
  8. package/app/server/routes/index.ts +5 -3
  9. package/config/app.config.ts +113 -0
  10. package/config/build.config.ts +24 -0
  11. package/config/database.config.ts +99 -0
  12. package/config/index.ts +68 -0
  13. package/config/logger.config.ts +27 -0
  14. package/config/runtime.config.ts +92 -0
  15. package/config/server.config.ts +46 -0
  16. package/config/services.config.ts +130 -0
  17. package/config/system.config.ts +105 -0
  18. package/core/build/bundler.ts +53 -5
  19. package/core/build/flux-plugins-generator.ts +315 -0
  20. package/core/build/index.ts +11 -7
  21. package/core/build/live-components-generator.ts +231 -0
  22. package/core/build/optimizer.ts +2 -54
  23. package/core/cli/index.ts +31 -13
  24. package/core/config/env.ts +38 -94
  25. package/core/config/runtime-config.ts +61 -58
  26. package/core/config/schema.ts +1 -0
  27. package/core/framework/server.ts +55 -11
  28. package/core/plugins/built-in/index.ts +7 -17
  29. package/core/plugins/built-in/static/index.ts +24 -10
  30. package/core/plugins/built-in/swagger/index.ts +228 -228
  31. package/core/plugins/built-in/vite/index.ts +374 -358
  32. package/core/plugins/dependency-manager.ts +5 -5
  33. package/core/plugins/manager.ts +57 -14
  34. package/core/plugins/registry.ts +3 -3
  35. package/core/server/index.ts +0 -1
  36. package/core/server/live/ComponentRegistry.ts +34 -8
  37. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  38. package/core/server/live/websocket-plugin.ts +434 -434
  39. package/core/server/middleware/README.md +488 -0
  40. package/core/server/middleware/elysia-helpers.ts +227 -0
  41. package/core/server/middleware/index.ts +25 -9
  42. package/core/server/plugins/static-files-plugin.ts +231 -231
  43. package/core/utils/config-schema.ts +484 -0
  44. package/core/utils/env.ts +306 -0
  45. package/core/utils/helpers.ts +9 -3
  46. package/core/utils/logger/colors.ts +114 -0
  47. package/core/utils/logger/config.ts +35 -0
  48. package/core/utils/logger/formatter.ts +82 -0
  49. package/core/utils/logger/group-logger.ts +101 -0
  50. package/core/utils/logger/index.ts +199 -250
  51. package/core/utils/logger/stack-trace.ts +92 -0
  52. package/core/utils/logger/startup-banner.ts +92 -0
  53. package/core/utils/logger/winston-logger.ts +152 -0
  54. package/core/utils/version.ts +5 -0
  55. package/create-fluxstack.ts +1 -0
  56. package/fluxstack.config.ts +6 -12
  57. package/package.json +117 -114
  58. package/plugins/crypto-auth/README.md +238 -0
  59. package/plugins/crypto-auth/client/CryptoAuthClient.ts +325 -0
  60. package/plugins/crypto-auth/client/components/AuthProvider.tsx +190 -0
  61. package/plugins/crypto-auth/client/components/LoginButton.tsx +155 -0
  62. package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +109 -0
  63. package/plugins/crypto-auth/client/components/SessionInfo.tsx +242 -0
  64. package/plugins/crypto-auth/client/components/index.ts +15 -0
  65. package/plugins/crypto-auth/client/index.ts +12 -0
  66. package/plugins/crypto-auth/index.ts +230 -0
  67. package/plugins/crypto-auth/package.json +65 -0
  68. package/plugins/crypto-auth/plugin.json +29 -0
  69. package/plugins/crypto-auth/server/AuthMiddleware.ts +237 -0
  70. package/plugins/crypto-auth/server/CryptoAuthService.ts +293 -0
  71. package/plugins/crypto-auth/server/index.ts +9 -0
  72. package/vite.config.ts +16 -0
  73. package/core/config/env-dynamic.ts +0 -326
  74. package/core/plugins/built-in/logger/index.ts +0 -180
  75. package/core/server/plugins/logger.ts +0 -47
  76. package/core/utils/env-runtime-v2.ts +0 -232
  77. package/core/utils/env-runtime.ts +0 -259
  78. package/core/utils/logger/formatters.ts +0 -222
  79. package/core/utils/logger/middleware.ts +0 -253
  80. package/core/utils/logger/performance.ts +0 -384
  81. package/core/utils/logger/transports.ts +0 -365
  82. package/core/utils/logger.ts +0 -106
@@ -1,180 +0,0 @@
1
- import type { Plugin, PluginContext, RequestContext, ResponseContext, ErrorContext } from "../../types"
2
-
3
- export const loggerPlugin: Plugin = {
4
- name: "logger",
5
- version: "1.0.0",
6
- description: "Enhanced logging plugin for FluxStack with request/response logging",
7
- author: "FluxStack Team",
8
- priority: 1000, // Logger should run first
9
- category: "core",
10
- tags: ["logging", "monitoring"],
11
-
12
- configSchema: {
13
- type: "object",
14
- properties: {
15
- logRequests: {
16
- type: "boolean",
17
- description: "Enable request logging"
18
- },
19
- logResponses: {
20
- type: "boolean",
21
- description: "Enable response logging"
22
- },
23
- logErrors: {
24
- type: "boolean",
25
- description: "Enable error logging"
26
- },
27
- includeHeaders: {
28
- type: "boolean",
29
- description: "Include headers in request/response logs"
30
- },
31
- includeBody: {
32
- type: "boolean",
33
- description: "Include body in request/response logs"
34
- },
35
- slowRequestThreshold: {
36
- type: "number",
37
- minimum: 0,
38
- description: "Threshold in ms to log slow requests"
39
- }
40
- },
41
- additionalProperties: false
42
- },
43
-
44
- defaultConfig: {
45
- logRequests: process.env.ENABLE_REQUEST_LOGS === 'true',
46
- logResponses: process.env.ENABLE_REQUEST_LOGS === 'true',
47
- logErrors: true,
48
- includeHeaders: false,
49
- includeBody: false,
50
- slowRequestThreshold: 1000
51
- },
52
-
53
- setup: async (context: PluginContext) => {
54
- context.logger.info("Enhanced logger plugin initialized", {
55
- environment: context.config.app?.name || 'fluxstack',
56
- logLevel: context.config.logging.level,
57
- format: context.config.logging.format
58
- })
59
- },
60
-
61
- onServerStart: async (context: PluginContext) => {
62
- context.logger.info("Logger plugin: Server started", {
63
- port: context.config.server.port,
64
- host: context.config.server.host,
65
- apiPrefix: context.config.server.apiPrefix
66
- })
67
- },
68
-
69
- onServerStop: async (context: PluginContext) => {
70
- context.logger.info("Logger plugin: Server stopped")
71
- },
72
-
73
- onRequest: async (context: RequestContext) => {
74
- const config = getPluginConfig(context)
75
-
76
- if (!config.logRequests) return
77
-
78
- const logData: any = {
79
- method: context.method,
80
- path: context.path,
81
- userAgent: context.headers['user-agent'],
82
- ip: context.headers['x-forwarded-for'] || context.headers['x-real-ip'] || 'unknown'
83
- }
84
-
85
- if (config.includeHeaders) {
86
- logData.headers = context.headers
87
- }
88
-
89
- if (config.includeBody && context.body) {
90
- logData.body = context.body
91
- }
92
-
93
- // Use a logger from context if available, otherwise create one
94
- const logger = (context as any).logger || console
95
- if (typeof logger.info === 'function') {
96
- logger.info(`→ ${context.method} ${context.path}`, logData)
97
- }
98
- },
99
-
100
- onResponse: async (context: ResponseContext) => {
101
- const config = getPluginConfig(context)
102
-
103
- if (!config.logResponses) return
104
-
105
- const logData: any = {
106
- method: context.method,
107
- path: context.path,
108
- statusCode: context.statusCode,
109
- duration: context.duration,
110
- size: context.size
111
- }
112
-
113
- if (config.includeHeaders) {
114
- const headers: Record<string, string> = {}
115
- context.response.headers.forEach((value, key) => {
116
- headers[key] = value
117
- })
118
- logData.responseHeaders = headers
119
- }
120
-
121
- // Determine log level based on status code and duration
122
- let logLevel = 'info'
123
- if (context.statusCode >= 400) {
124
- logLevel = 'warn'
125
- }
126
- if (context.statusCode >= 500) {
127
- logLevel = 'error'
128
- }
129
- if (context.duration > config.slowRequestThreshold) {
130
- logLevel = 'warn'
131
- }
132
-
133
- const logger = (context as any).logger || console
134
- const logMessage = `← ${context.method} ${context.path} ${context.statusCode} ${context.duration}ms`
135
-
136
- if (typeof logger[logLevel] === 'function') {
137
- logger[logLevel](logMessage, logData)
138
- }
139
- },
140
-
141
- onError: async (context: ErrorContext) => {
142
- const config = getPluginConfig(context)
143
-
144
- if (!config.logErrors) return
145
-
146
- // Skip logging for NOT_FOUND errors unless explicitly enabled
147
- if (context.error.message === 'NOT_FOUND' && !process.env.ENABLE_NOT_FOUND_LOGS) {
148
- return
149
- }
150
-
151
- const logData: any = {
152
- method: context.method,
153
- path: context.path,
154
- duration: context.duration,
155
- error: {
156
- name: context.error.name,
157
- message: context.error.message,
158
- stack: context.error.stack
159
- }
160
- }
161
-
162
- if (config.includeHeaders) {
163
- logData.headers = context.headers
164
- }
165
-
166
- const logger = (context as any).logger || console
167
- if (typeof logger.error === 'function') {
168
- logger.error(`✗ ${context.method} ${context.path} - ${context.error.message}`, logData)
169
- }
170
- }
171
- }
172
-
173
- // Helper function to get plugin config from context
174
- function getPluginConfig(_context: any) {
175
- // In a real implementation, this would get the config from the plugin context
176
- // For now, return default config
177
- return loggerPlugin.defaultConfig || {}
178
- }
179
-
180
- export default loggerPlugin
@@ -1,47 +0,0 @@
1
- import type { Plugin, PluginContext } from "../../types"
2
- import { log } from "../../utils/logger"
3
-
4
- export const loggerPlugin: Plugin = {
5
- name: "logger",
6
- setup: (context: PluginContext) => {
7
- const logLevel = process.env.LOG_LEVEL || context.config.logging?.level || 'info'
8
- const isDev = process.env.NODE_ENV === 'development'
9
-
10
- log.plugin("logger", "Logger plugin initialized", {
11
- logLevel,
12
- environment: process.env.NODE_ENV || 'development'
13
- })
14
-
15
- // Only enable verbose request logging if explicitly requested
16
- if (process.env.ENABLE_REQUEST_LOGS === 'true') {
17
- // Setup logging hooks on the Elysia app
18
- context.app.onRequest(({ request }: { request: Request }) => {
19
- const startTime = Date.now()
20
- const path = new URL(request.url).pathname
21
-
22
- // Store start time for duration calculation
23
- ;(request as any).__startTime = startTime
24
-
25
- log.request(request.method, path)
26
- })
27
-
28
- context.app.onResponse(({ request, set }: { request: Request, set: any }) => {
29
- const duration = Date.now() - ((request as any).__startTime || Date.now())
30
- const path = new URL(request.url).pathname
31
-
32
- log.request(request.method, path, set.status || 200, duration)
33
- })
34
- }
35
-
36
- // Always log errors
37
- context.app.onError(({ error, request }: { error: Error, request: Request }) => {
38
- const duration = Date.now() - ((request as any).__startTime || Date.now())
39
- const path = new URL(request.url).pathname
40
-
41
- log.error(`${request.method} ${path} - ${error.message}`, {
42
- duration,
43
- stack: error.stack
44
- })
45
- })
46
- }
47
- }
@@ -1,232 +0,0 @@
1
- /**
2
- * Runtime Environment Loader V2 - Simplified API
3
- * Mais elegante com casting automático e acesso direto
4
- */
5
-
6
- /**
7
- * Enhanced environment variable loader with smart casting
8
- */
9
- class SmartEnvLoader {
10
- private envAccessor: () => Record<string, string | undefined>
11
-
12
- constructor() {
13
- this.envAccessor = this.createDynamicAccessor()
14
- }
15
-
16
- private createDynamicAccessor(): () => Record<string, string | undefined> {
17
- const globalScope = globalThis as any
18
-
19
- return () => {
20
- // Try Bun.env first (most reliable in Bun runtime)
21
- if (globalScope['Bun'] && globalScope['Bun']['env']) {
22
- return globalScope['Bun']['env']
23
- }
24
-
25
- // Fallback to process.env with dynamic access
26
- if (globalScope['process'] && globalScope['process']['env']) {
27
- return globalScope['process']['env']
28
- }
29
-
30
- // Final fallback
31
- const proc = eval('typeof process !== "undefined" ? process : null')
32
- return proc?.env || {}
33
- }
34
- }
35
-
36
- /**
37
- * Smart get with automatic type conversion based on default value
38
- */
39
- get<T>(key: string, defaultValue?: T): T {
40
- const env = this.envAccessor()
41
- const value = env[key]
42
-
43
- if (!value || value === '') {
44
- return defaultValue as T
45
- }
46
-
47
- // Auto-detect type from default value
48
- if (typeof defaultValue === 'number') {
49
- const parsed = parseInt(value, 10)
50
- return (isNaN(parsed) ? defaultValue : parsed) as T
51
- }
52
-
53
- if (typeof defaultValue === 'boolean') {
54
- return ['true', '1', 'yes', 'on'].includes(value.toLowerCase()) as T
55
- }
56
-
57
- if (Array.isArray(defaultValue)) {
58
- return value.split(',').map(v => v.trim()).filter(Boolean) as T
59
- }
60
-
61
- if (typeof defaultValue === 'object' && defaultValue !== null) {
62
- try {
63
- return JSON.parse(value) as T
64
- } catch {
65
- return defaultValue
66
- }
67
- }
68
-
69
- return value as T
70
- }
71
-
72
- /**
73
- * Check if environment variable exists
74
- */
75
- has(key: string): boolean {
76
- const env = this.envAccessor()
77
- return key in env && env[key] !== undefined && env[key] !== ''
78
- }
79
-
80
- /**
81
- * Get all environment variables
82
- */
83
- all(): Record<string, string> {
84
- const env = this.envAccessor()
85
- const result: Record<string, string> = {}
86
-
87
- for (const [key, value] of Object.entries(env)) {
88
- if (value !== undefined && value !== '') {
89
- result[key] = value
90
- }
91
- }
92
-
93
- return result
94
- }
95
- }
96
-
97
- // Create singleton instance
98
- const smartEnv = new SmartEnvLoader()
99
-
100
- /**
101
- * Simplified env API with smart casting
102
- */
103
- export const env = {
104
- /**
105
- * Smart get - automatically casts based on default value type
106
- * Usage:
107
- * env.get('PORT', 3000) -> number
108
- * env.get('DEBUG', false) -> boolean
109
- * env.get('ORIGINS', ['*']) -> string[]
110
- * env.get('HOST', 'localhost') -> string
111
- */
112
- get: <T>(key: string, defaultValue?: T): T => smartEnv.get(key, defaultValue),
113
-
114
- /**
115
- * Check if env var exists
116
- */
117
- has: (key: string) => smartEnv.has(key),
118
-
119
- /**
120
- * Get all env vars
121
- */
122
- all: () => smartEnv.all(),
123
-
124
- // Common environment variables as properties with smart defaults
125
- get NODE_ENV() { return this.get('NODE_ENV', 'development') },
126
- get PORT() { return this.get('PORT', 3000) },
127
- get HOST() { return this.get('HOST', 'localhost') },
128
- get DEBUG() { return this.get('DEBUG', false) },
129
- get LOG_LEVEL() { return this.get('LOG_LEVEL', 'info') },
130
- get DATABASE_URL() { return this.get('DATABASE_URL', '') },
131
- get JWT_SECRET() { return this.get('JWT_SECRET', '') },
132
- get CORS_ORIGINS() { return this.get('CORS_ORIGINS', ['*']) },
133
- get VITE_PORT() { return this.get('VITE_PORT', 5173) },
134
- get API_PREFIX() { return this.get('API_PREFIX', '/api') },
135
-
136
- // App specific
137
- get FLUXSTACK_APP_NAME() { return this.get('FLUXSTACK_APP_NAME', 'FluxStack') },
138
- get FLUXSTACK_APP_VERSION() { return this.get('FLUXSTACK_APP_VERSION', '1.0.0') },
139
-
140
- // Monitoring
141
- get ENABLE_MONITORING() { return this.get('ENABLE_MONITORING', false) },
142
- get ENABLE_SWAGGER() { return this.get('ENABLE_SWAGGER', true) },
143
- get ENABLE_METRICS() { return this.get('ENABLE_METRICS', false) },
144
-
145
- // Database
146
- get DB_HOST() { return this.get('DB_HOST', 'localhost') },
147
- get DB_PORT() { return this.get('DB_PORT', 5432) },
148
- get DB_NAME() { return this.get('DB_NAME', '') },
149
- get DB_USER() { return this.get('DB_USER', '') },
150
- get DB_PASSWORD() { return this.get('DB_PASSWORD', '') },
151
- get DB_SSL() { return this.get('DB_SSL', false) },
152
-
153
- // SMTP
154
- get SMTP_HOST() { return this.get('SMTP_HOST', '') },
155
- get SMTP_PORT() { return this.get('SMTP_PORT', 587) },
156
- get SMTP_USER() { return this.get('SMTP_USER', '') },
157
- get SMTP_PASSWORD() { return this.get('SMTP_PASSWORD', '') },
158
- get SMTP_SECURE() { return this.get('SMTP_SECURE', false) }
159
- }
160
-
161
- /**
162
- * Create namespaced environment access
163
- * Usage: const db = createNamespace('DATABASE_')
164
- * db.get('URL') -> reads DATABASE_URL
165
- */
166
- export function createNamespace(prefix: string) {
167
- return {
168
- get: <T>(key: string, defaultValue?: T): T =>
169
- smartEnv.get(`${prefix}${key}`, defaultValue),
170
-
171
- has: (key: string) => smartEnv.has(`${prefix}${key}`),
172
-
173
- all: () => {
174
- const allEnv = smartEnv.all()
175
- const namespaced: Record<string, string> = {}
176
-
177
- for (const [key, value] of Object.entries(allEnv)) {
178
- if (key.startsWith(prefix)) {
179
- namespaced[key.slice(prefix.length)] = value
180
- }
181
- }
182
-
183
- return namespaced
184
- }
185
- }
186
- }
187
-
188
- /**
189
- * Environment validation
190
- */
191
- export const validate = {
192
- require(keys: string[]): void {
193
- const missing = keys.filter(key => !smartEnv.has(key))
194
- if (missing.length > 0) {
195
- throw new Error(`Missing required environment variables: ${missing.join(', ')}`)
196
- }
197
- },
198
-
199
- oneOf(key: string, validValues: string[]): void {
200
- const value = smartEnv.get(key, '')
201
- if (value && !validValues.includes(value)) {
202
- throw new Error(`${key} must be one of: ${validValues.join(', ')}, got: ${value}`)
203
- }
204
- }
205
- }
206
-
207
- /**
208
- * Convenience functions
209
- */
210
- export const helpers = {
211
- isDevelopment: () => env.NODE_ENV === 'development',
212
- isProduction: () => env.NODE_ENV === 'production',
213
- isTest: () => env.NODE_ENV === 'test',
214
-
215
- getDatabaseUrl: () => {
216
- const url = env.DATABASE_URL
217
- if (url) return url
218
-
219
- const { DB_HOST, DB_PORT, DB_NAME, DB_USER, DB_PASSWORD } = env
220
- if (DB_HOST && DB_NAME) {
221
- const auth = DB_USER ? `${DB_USER}:${DB_PASSWORD}@` : ''
222
- return `postgres://${auth}${DB_HOST}:${DB_PORT}/${DB_NAME}`
223
- }
224
-
225
- return null
226
- },
227
-
228
- getServerUrl: () => `http://${env.HOST}:${env.PORT}`,
229
- getClientUrl: () => `http://${env.HOST}:${env.VITE_PORT}`
230
- }
231
-
232
- export default env