create-fluxstack 1.4.0 → 1.5.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.
- package/.env.example +8 -1
- package/CRYPTO-AUTH-MIDDLEWARE-GUIDE.md +475 -0
- package/CRYPTO-AUTH-MIDDLEWARES.md +473 -0
- package/CRYPTO-AUTH-USAGE.md +491 -0
- package/EXEMPLO-ROTA-PROTEGIDA.md +347 -0
- package/QUICK-START-CRYPTO-AUTH.md +221 -0
- package/app/client/src/App.tsx +4 -1
- package/app/client/src/pages/CryptoAuthPage.tsx +394 -0
- package/app/server/index.ts +4 -0
- package/app/server/routes/crypto-auth-demo.routes.ts +167 -0
- package/app/server/routes/example-with-crypto-auth.routes.ts +235 -0
- package/app/server/routes/exemplo-posts.routes.ts +161 -0
- package/app/server/routes/index.ts +5 -1
- package/config/index.ts +9 -1
- package/core/cli/generators/index.ts +5 -2
- package/core/cli/generators/plugin.ts +580 -0
- package/core/cli/generators/template-engine.ts +5 -0
- package/core/cli/index.ts +88 -3
- package/core/cli/plugin-discovery.ts +33 -12
- package/core/framework/server.ts +10 -0
- package/core/plugins/dependency-manager.ts +89 -22
- package/core/plugins/index.ts +4 -0
- package/core/plugins/manager.ts +3 -2
- package/core/plugins/module-resolver.ts +216 -0
- package/core/plugins/registry.ts +28 -1
- package/core/utils/logger/index.ts +4 -0
- package/core/utils/version.ts +1 -1
- package/create-fluxstack.ts +117 -8
- package/fluxstack.config.ts +253 -114
- package/package.json +117 -117
- package/plugins/crypto-auth/README.md +722 -172
- package/plugins/crypto-auth/ai-context.md +1282 -0
- package/plugins/crypto-auth/cli/make-protected-route.command.ts +383 -0
- package/plugins/crypto-auth/client/CryptoAuthClient.ts +136 -159
- package/plugins/crypto-auth/client/components/AuthProvider.tsx +35 -94
- package/plugins/crypto-auth/client/components/LoginButton.tsx +36 -53
- package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +17 -37
- package/plugins/crypto-auth/client/components/index.ts +1 -4
- package/plugins/crypto-auth/client/index.ts +1 -1
- package/plugins/crypto-auth/config/index.ts +34 -0
- package/plugins/crypto-auth/index.ts +84 -152
- package/plugins/crypto-auth/package.json +65 -64
- package/plugins/crypto-auth/server/AuthMiddleware.ts +19 -75
- package/plugins/crypto-auth/server/CryptoAuthService.ts +60 -167
- package/plugins/crypto-auth/server/index.ts +15 -2
- package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +65 -0
- package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +26 -0
- package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +76 -0
- package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +45 -0
- package/plugins/crypto-auth/server/middlewares/helpers.ts +140 -0
- package/plugins/crypto-auth/server/middlewares/index.ts +22 -0
- package/plugins/crypto-auth/server/middlewares.ts +19 -0
- package/test-crypto-auth.ts +101 -0
- package/plugins/crypto-auth/client/components/SessionInfo.tsx +0 -242
- package/plugins/crypto-auth/plugin.json +0 -29
package/create-fluxstack.ts
CHANGED
|
@@ -5,16 +5,17 @@ import { resolve, join } from 'path'
|
|
|
5
5
|
import { existsSync, mkdirSync, cpSync, writeFileSync, readFileSync } from 'fs'
|
|
6
6
|
import chalk from 'chalk'
|
|
7
7
|
import ora from 'ora'
|
|
8
|
+
import { FLUXSTACK_VERSION } from './core/utils/version'
|
|
8
9
|
|
|
9
10
|
const logo = `
|
|
10
|
-
⚡ ███████ ██ ██ ██ ██ ██ ███████ ████████ █████ ██████ ██ ██
|
|
11
|
-
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
12
|
-
█████ ██ ██ ██ ███ ███████ ██ ███████ ██ █████
|
|
13
|
-
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
14
|
-
██ ███████ ██████ ██ ██ ███████ ██ ██ ██ ██████ ██ ██
|
|
11
|
+
⚡ ███████ ██ ██ ██ ██ ██ ███████ ████████ █████ ██████ ██ ██
|
|
12
|
+
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
13
|
+
█████ ██ ██ ██ ███ ███████ ██ ███████ ██ █████
|
|
14
|
+
██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██ ██
|
|
15
|
+
██ ███████ ██████ ██ ██ ███████ ██ ██ ██ ██████ ██ ██
|
|
15
16
|
|
|
16
17
|
${chalk.cyan('💫 Powered by Bun - The Divine Runtime ⚡')}
|
|
17
|
-
${chalk.gray(
|
|
18
|
+
${chalk.gray(`FluxStack v${FLUXSTACK_VERSION} - Creates full-stack TypeScript apps`)}
|
|
18
19
|
`
|
|
19
20
|
|
|
20
21
|
program
|
|
@@ -58,6 +59,7 @@ program
|
|
|
58
59
|
'core',
|
|
59
60
|
'app',
|
|
60
61
|
'config', // ✅ CRITICAL: Copy config folder with declarative configs
|
|
62
|
+
// 'plugins', // TODO: Copy when crypto-auth plugin is complete
|
|
61
63
|
'ai-context', // ✅ CRITICAL: Copy AI documentation for users
|
|
62
64
|
'bun.lock', // ✅ CRITICAL: Copy lockfile to maintain working versions
|
|
63
65
|
'package.json', // ✅ Copy real package.json from framework
|
|
@@ -67,15 +69,122 @@ program
|
|
|
67
69
|
'CLAUDE.md', // ✅ Project instructions for AI assistants
|
|
68
70
|
'README.md'
|
|
69
71
|
]
|
|
70
|
-
|
|
72
|
+
|
|
71
73
|
for (const file of filesToCopy) {
|
|
72
74
|
const sourcePath = join(frameworkDir, file)
|
|
73
75
|
const destPath = join(projectPath, file)
|
|
74
|
-
|
|
76
|
+
|
|
75
77
|
if (existsSync(sourcePath)) {
|
|
76
78
|
cpSync(sourcePath, destPath, { recursive: true })
|
|
77
79
|
}
|
|
78
80
|
}
|
|
81
|
+
|
|
82
|
+
// Create empty plugins directory for user plugins
|
|
83
|
+
const pluginsDir = join(projectPath, 'plugins')
|
|
84
|
+
mkdirSync(pluginsDir, { recursive: true })
|
|
85
|
+
|
|
86
|
+
// Create a README in plugins folder
|
|
87
|
+
const pluginsReadme = `# Plugins
|
|
88
|
+
|
|
89
|
+
This folder is for your custom FluxStack plugins.
|
|
90
|
+
|
|
91
|
+
## 📖 Documentation
|
|
92
|
+
|
|
93
|
+
For complete plugin development guide, see:
|
|
94
|
+
- \`ai-context/development/plugins-guide.md\` - Full plugin documentation
|
|
95
|
+
- \`ai-context/examples/\` - Plugin examples
|
|
96
|
+
|
|
97
|
+
## 📦 Available CLI Commands
|
|
98
|
+
|
|
99
|
+
\`\`\`bash
|
|
100
|
+
# Create a new plugin
|
|
101
|
+
bun run cli make:plugin my-plugin # Basic plugin
|
|
102
|
+
bun run cli make:plugin my-plugin --template full # Full plugin (server + client)
|
|
103
|
+
bun run cli make:plugin my-plugin --template server # Server-only plugin
|
|
104
|
+
|
|
105
|
+
# Manage plugin dependencies
|
|
106
|
+
bun run cli plugin:deps install # Install plugin dependencies
|
|
107
|
+
bun run cli plugin:deps list # List plugin dependencies
|
|
108
|
+
bun run cli plugin:deps check # Check for conflicts
|
|
109
|
+
bun run cli plugin:deps clean # Clean unused dependencies
|
|
110
|
+
\`\`\`
|
|
111
|
+
|
|
112
|
+
## 🔌 Plugin Structure
|
|
113
|
+
|
|
114
|
+
\`\`\`
|
|
115
|
+
plugins/
|
|
116
|
+
├── my-plugin/
|
|
117
|
+
│ ├── plugin.json # Plugin metadata (name, version, dependencies)
|
|
118
|
+
│ ├── index.ts # Plugin entry point (server-side hooks)
|
|
119
|
+
│ ├── server/ # Server-side code (optional)
|
|
120
|
+
│ └── client/ # Client-side code (optional)
|
|
121
|
+
\`\`\`
|
|
122
|
+
|
|
123
|
+
## ⚡ Quick Start
|
|
124
|
+
|
|
125
|
+
1. Create your plugin folder: \`plugins/my-plugin/\`
|
|
126
|
+
2. Create \`plugin.json\` with metadata
|
|
127
|
+
3. Create \`index.ts\` with your plugin logic
|
|
128
|
+
4. Use \`bun run cli plugin:deps install\` if you need extra dependencies
|
|
129
|
+
|
|
130
|
+
## 🔌 Intercepting Requests
|
|
131
|
+
|
|
132
|
+
Plugins can intercept and modify requests using hooks:
|
|
133
|
+
|
|
134
|
+
\`\`\`typescript
|
|
135
|
+
// plugins/my-plugin/index.ts
|
|
136
|
+
import type { FluxStackPlugin, PluginContext } from '@/core/types/plugin'
|
|
137
|
+
|
|
138
|
+
export class MyPlugin implements FluxStackPlugin {
|
|
139
|
+
name = 'my-plugin'
|
|
140
|
+
version = '1.0.0'
|
|
141
|
+
|
|
142
|
+
// Intercept every request
|
|
143
|
+
async onRequest(context: PluginContext, request: Request): Promise<void> {
|
|
144
|
+
// Example: Add custom headers
|
|
145
|
+
const url = new URL(request.url)
|
|
146
|
+
console.log(\`[\${this.name}] Request to: \${url.pathname}\`)
|
|
147
|
+
|
|
148
|
+
// Example: Validate authentication
|
|
149
|
+
const token = request.headers.get('Authorization')
|
|
150
|
+
if (!token && url.pathname.startsWith('/api/protected')) {
|
|
151
|
+
throw new Error('Unauthorized')
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Intercept every response
|
|
156
|
+
async onResponse(context: PluginContext, response: Response): Promise<void> {
|
|
157
|
+
console.log(\`[\${this.name}] Response status: \${response.status}\`)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Handle errors
|
|
161
|
+
async onError(context: PluginContext, error: Error): Promise<void> {
|
|
162
|
+
console.error(\`[\${this.name}] Error:\`, error.message)
|
|
163
|
+
// Example: Send to error tracking service
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
\`\`\`
|
|
167
|
+
|
|
168
|
+
## 📋 Available Hooks
|
|
169
|
+
|
|
170
|
+
- **\`setup\`**: Initialize plugin resources (called once at startup)
|
|
171
|
+
- **\`onServerStart\`**: Run when server starts
|
|
172
|
+
- **\`onRequest\`**: Intercept incoming requests (before route handlers)
|
|
173
|
+
- **\`onResponse\`**: Intercept outgoing responses (after route handlers)
|
|
174
|
+
- **\`onError\`**: Handle errors globally
|
|
175
|
+
|
|
176
|
+
## 💡 Common Use Cases
|
|
177
|
+
|
|
178
|
+
- **Authentication**: Validate tokens in \`onRequest\`
|
|
179
|
+
- **Logging**: Log requests/responses for analytics
|
|
180
|
+
- **Rate Limiting**: Track request counts per IP
|
|
181
|
+
- **CORS**: Add headers in \`onResponse\`
|
|
182
|
+
- **Request Transformation**: Modify request body/headers
|
|
183
|
+
- **Response Transformation**: Add custom headers, compress responses
|
|
184
|
+
|
|
185
|
+
See the documentation for detailed examples and best practices.
|
|
186
|
+
`
|
|
187
|
+
writeFileSync(join(pluginsDir, 'README.md'), pluginsReadme)
|
|
79
188
|
|
|
80
189
|
// Generate .gitignore using template (instead of copying)
|
|
81
190
|
const gitignoreContent = `# Dependencies
|
package/fluxstack.config.ts
CHANGED
|
@@ -1,74 +1,261 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FluxStack Configuration
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* ✅ Using declarative config system with schema validation and type inference
|
|
4
|
+
* Laravel-inspired declarative configuration with full type safety
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { FluxStackConfig } from './core/config/schema'
|
|
8
|
+
import { defineConfig, config as configHelpers } from './core/utils/config-schema'
|
|
8
9
|
import { env, helpers } from './core/utils/env'
|
|
9
10
|
|
|
10
11
|
console.log(`🔧 Loading FluxStack config for ${env.NODE_ENV} environment`)
|
|
11
12
|
|
|
12
|
-
//
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// 📋 DECLARATIVE CONFIG SCHEMAS
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Application Configuration Schema
|
|
19
|
+
*/
|
|
20
|
+
const appConfigSchema = {
|
|
21
|
+
name: configHelpers.string('FLUXSTACK_APP_NAME', 'FluxStack', true),
|
|
22
|
+
version: configHelpers.string('FLUXSTACK_APP_VERSION', '1.0.0', true),
|
|
23
|
+
description: configHelpers.string('FLUXSTACK_APP_DESCRIPTION', 'A FluxStack application')
|
|
24
|
+
} as const
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* CORS Configuration Schema
|
|
28
|
+
*/
|
|
29
|
+
const corsConfigSchema = {
|
|
30
|
+
origins: configHelpers.array('CORS_ORIGINS', ['http://localhost:3000', 'http://localhost:5173']),
|
|
31
|
+
methods: configHelpers.array('CORS_METHODS', ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']),
|
|
32
|
+
headers: configHelpers.array('CORS_HEADERS', ['Content-Type', 'Authorization']),
|
|
33
|
+
credentials: configHelpers.boolean('CORS_CREDENTIALS', false),
|
|
34
|
+
maxAge: configHelpers.number('CORS_MAX_AGE', 86400)
|
|
35
|
+
} as const
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Server Configuration Schema
|
|
39
|
+
*/
|
|
40
|
+
const serverConfigSchema = {
|
|
41
|
+
port: configHelpers.number('PORT', 3000, true),
|
|
42
|
+
host: configHelpers.string('HOST', 'localhost', true),
|
|
43
|
+
apiPrefix: configHelpers.string('API_PREFIX', '/api', true)
|
|
44
|
+
} as const
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Client Proxy Configuration Schema
|
|
48
|
+
*/
|
|
49
|
+
const clientProxyConfigSchema = {
|
|
50
|
+
target: {
|
|
51
|
+
type: 'string' as const,
|
|
52
|
+
env: 'PROXY_TARGET',
|
|
53
|
+
default: helpers.getServerUrl(),
|
|
54
|
+
required: false
|
|
55
|
+
},
|
|
56
|
+
changeOrigin: configHelpers.boolean('PROXY_CHANGE_ORIGIN', true)
|
|
57
|
+
} as const
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Client Build Configuration Schema
|
|
61
|
+
*/
|
|
62
|
+
const clientBuildConfigSchema = {
|
|
63
|
+
sourceMaps: configHelpers.boolean('CLIENT_SOURCEMAPS', helpers.isDevelopment()),
|
|
64
|
+
minify: configHelpers.boolean('CLIENT_MINIFY', helpers.isProduction()),
|
|
65
|
+
target: configHelpers.string('CLIENT_TARGET', 'esnext'),
|
|
66
|
+
outDir: configHelpers.string('CLIENT_OUTDIR', 'dist/client')
|
|
67
|
+
} as const
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Client Configuration Schema
|
|
71
|
+
*/
|
|
72
|
+
const clientConfigSchema = {
|
|
73
|
+
port: configHelpers.number('VITE_PORT', 5173, true)
|
|
74
|
+
} as const
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Build Optimization Configuration Schema
|
|
78
|
+
*/
|
|
79
|
+
const buildOptimizationConfigSchema = {
|
|
80
|
+
minify: configHelpers.boolean('BUILD_MINIFY', helpers.isProduction()),
|
|
81
|
+
treeshake: configHelpers.boolean('BUILD_TREESHAKE', helpers.isProduction()),
|
|
82
|
+
compress: configHelpers.boolean('BUILD_COMPRESS', helpers.isProduction()),
|
|
83
|
+
splitChunks: configHelpers.boolean('BUILD_SPLIT_CHUNKS', true),
|
|
84
|
+
bundleAnalyzer: configHelpers.boolean('BUILD_ANALYZER', helpers.isDevelopment())
|
|
85
|
+
} as const
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Build Configuration Schema
|
|
89
|
+
*/
|
|
90
|
+
const buildConfigSchema = {
|
|
91
|
+
target: configHelpers.enum('BUILD_TARGET', ['bun', 'node', 'docker'] as const, 'bun'),
|
|
92
|
+
outDir: configHelpers.string('BUILD_OUTDIR', 'dist'),
|
|
93
|
+
sourceMaps: configHelpers.boolean('BUILD_SOURCEMAPS', !helpers.isProduction()),
|
|
94
|
+
minify: configHelpers.boolean('BUILD_MINIFY', helpers.isProduction()),
|
|
95
|
+
treeshake: configHelpers.boolean('BUILD_TREESHAKE', helpers.isProduction()),
|
|
96
|
+
clean: configHelpers.boolean('BUILD_CLEAN', true)
|
|
97
|
+
} as const
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Plugins Configuration Schema
|
|
101
|
+
*/
|
|
102
|
+
const pluginsConfigSchema = {
|
|
103
|
+
enabled: configHelpers.array('FLUXSTACK_PLUGINS_ENABLED', ['logger', 'swagger', 'vite', 'cors', 'static-files', 'crypto-auth']),
|
|
104
|
+
disabled: configHelpers.array('FLUXSTACK_PLUGINS_DISABLED', [])
|
|
105
|
+
} as const
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Logging Configuration Schema
|
|
109
|
+
*/
|
|
110
|
+
const loggingConfigSchema = {
|
|
111
|
+
level: configHelpers.enum('LOG_LEVEL', ['debug', 'info', 'warn', 'error'] as const, helpers.isDevelopment() ? 'debug' : 'info'),
|
|
112
|
+
format: configHelpers.enum('LOG_FORMAT', ['json', 'pretty'] as const, helpers.isDevelopment() ? 'pretty' : 'json')
|
|
113
|
+
} as const
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Monitoring Metrics Configuration Schema
|
|
117
|
+
*/
|
|
118
|
+
const monitoringMetricsConfigSchema = {
|
|
119
|
+
enabled: configHelpers.boolean('ENABLE_METRICS', false),
|
|
120
|
+
collectInterval: configHelpers.number('METRICS_INTERVAL', 5000),
|
|
121
|
+
httpMetrics: configHelpers.boolean('HTTP_METRICS', true),
|
|
122
|
+
systemMetrics: configHelpers.boolean('SYSTEM_METRICS', true),
|
|
123
|
+
customMetrics: configHelpers.boolean('CUSTOM_METRICS', false)
|
|
124
|
+
} as const
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Monitoring Profiling Configuration Schema
|
|
128
|
+
*/
|
|
129
|
+
const monitoringProfilingConfigSchema = {
|
|
130
|
+
enabled: configHelpers.boolean('PROFILING_ENABLED', false),
|
|
131
|
+
sampleRate: configHelpers.number('PROFILING_SAMPLE_RATE', 0.1),
|
|
132
|
+
memoryProfiling: configHelpers.boolean('MEMORY_PROFILING', false),
|
|
133
|
+
cpuProfiling: configHelpers.boolean('CPU_PROFILING', false)
|
|
134
|
+
} as const
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Monitoring Configuration Schema
|
|
138
|
+
*/
|
|
139
|
+
const monitoringConfigSchema = {
|
|
140
|
+
enabled: configHelpers.boolean('ENABLE_MONITORING', false),
|
|
141
|
+
exporters: configHelpers.array('MONITORING_EXPORTERS', [])
|
|
142
|
+
} as const
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Database Configuration Schema (Optional)
|
|
146
|
+
*/
|
|
147
|
+
const databaseConfigSchema = {
|
|
148
|
+
url: configHelpers.string('DATABASE_URL', ''),
|
|
149
|
+
host: configHelpers.string('DB_HOST', ''),
|
|
150
|
+
port: configHelpers.number('DB_PORT', 5432),
|
|
151
|
+
database: configHelpers.string('DB_NAME', ''),
|
|
152
|
+
user: configHelpers.string('DB_USER', ''),
|
|
153
|
+
password: configHelpers.string('DB_PASSWORD', ''),
|
|
154
|
+
ssl: configHelpers.boolean('DB_SSL', false),
|
|
155
|
+
poolSize: configHelpers.number('DB_POOL_SIZE', 10)
|
|
156
|
+
} as const
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Auth Configuration Schema (Optional)
|
|
160
|
+
*/
|
|
161
|
+
const authConfigSchema = {
|
|
162
|
+
secret: configHelpers.string('JWT_SECRET', ''),
|
|
163
|
+
expiresIn: configHelpers.string('JWT_EXPIRES_IN', '24h'),
|
|
164
|
+
algorithm: configHelpers.string('JWT_ALGORITHM', 'HS256'),
|
|
165
|
+
issuer: configHelpers.string('JWT_ISSUER', '')
|
|
166
|
+
} as const
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Email Configuration Schema (Optional)
|
|
170
|
+
*/
|
|
171
|
+
const emailConfigSchema = {
|
|
172
|
+
host: configHelpers.string('SMTP_HOST', ''),
|
|
173
|
+
port: configHelpers.number('SMTP_PORT', 587),
|
|
174
|
+
user: configHelpers.string('SMTP_USER', ''),
|
|
175
|
+
password: configHelpers.string('SMTP_PASSWORD', ''),
|
|
176
|
+
secure: configHelpers.boolean('SMTP_SECURE', false),
|
|
177
|
+
from: configHelpers.string('SMTP_FROM', '')
|
|
178
|
+
} as const
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Storage Configuration Schema (Optional)
|
|
182
|
+
*/
|
|
183
|
+
const storageConfigSchema = {
|
|
184
|
+
uploadPath: configHelpers.string('UPLOAD_PATH', ''),
|
|
185
|
+
maxFileSize: configHelpers.number('MAX_FILE_SIZE', 10485760), // 10MB
|
|
186
|
+
allowedTypes: configHelpers.array('ALLOWED_FILE_TYPES', []),
|
|
187
|
+
provider: configHelpers.enum('STORAGE_PROVIDER', ['local', 's3', 'gcs'] as const, 'local')
|
|
188
|
+
} as const
|
|
189
|
+
|
|
190
|
+
// ============================================================================
|
|
191
|
+
// ⚡ LOAD CONFIGURATIONS USING DECLARATIVE SYSTEM
|
|
192
|
+
// ============================================================================
|
|
193
|
+
|
|
194
|
+
const appConfig = defineConfig(appConfigSchema)
|
|
195
|
+
const corsConfig = defineConfig(corsConfigSchema)
|
|
196
|
+
const serverConfig = defineConfig(serverConfigSchema)
|
|
197
|
+
const clientProxyConfig = defineConfig(clientProxyConfigSchema)
|
|
198
|
+
const clientBuildConfig = defineConfig(clientBuildConfigSchema)
|
|
199
|
+
const clientConfig = defineConfig(clientConfigSchema)
|
|
200
|
+
const buildOptimizationConfig = defineConfig(buildOptimizationConfigSchema)
|
|
201
|
+
const buildConfig = defineConfig(buildConfigSchema)
|
|
202
|
+
const pluginsConfig = defineConfig(pluginsConfigSchema)
|
|
203
|
+
const loggingConfig = defineConfig(loggingConfigSchema)
|
|
204
|
+
const monitoringMetricsConfig = defineConfig(monitoringMetricsConfigSchema)
|
|
205
|
+
const monitoringProfilingConfig = defineConfig(monitoringProfilingConfigSchema)
|
|
206
|
+
const monitoringConfig = defineConfig(monitoringConfigSchema)
|
|
207
|
+
|
|
208
|
+
// Optional configs (only load if env vars are present)
|
|
209
|
+
const databaseConfig = (env.has('DATABASE_URL') || env.has('DATABASE_HOST'))
|
|
210
|
+
? defineConfig(databaseConfigSchema)
|
|
211
|
+
: undefined
|
|
212
|
+
|
|
213
|
+
const authConfig = env.has('JWT_SECRET')
|
|
214
|
+
? defineConfig(authConfigSchema)
|
|
215
|
+
: undefined
|
|
216
|
+
|
|
217
|
+
const emailConfig = env.has('SMTP_HOST')
|
|
218
|
+
? defineConfig(emailConfigSchema)
|
|
219
|
+
: undefined
|
|
220
|
+
|
|
221
|
+
const storageConfig = (env.has('UPLOAD_PATH') || env.has('STORAGE_PROVIDER'))
|
|
222
|
+
? defineConfig(storageConfigSchema)
|
|
223
|
+
: undefined
|
|
224
|
+
|
|
225
|
+
// ============================================================================
|
|
226
|
+
// 🚀 MAIN FLUXSTACK CONFIGURATION
|
|
227
|
+
// ============================================================================
|
|
228
|
+
|
|
13
229
|
export const config: FluxStackConfig = {
|
|
14
230
|
// Application metadata
|
|
15
|
-
app:
|
|
16
|
-
name: env.FLUXSTACK_APP_NAME, // Direto! (string)
|
|
17
|
-
version: env.FLUXSTACK_APP_VERSION, // Direto! (string)
|
|
18
|
-
description: env.get('FLUXSTACK_APP_DESCRIPTION', 'A FluxStack application')
|
|
19
|
-
},
|
|
231
|
+
app: appConfig,
|
|
20
232
|
|
|
21
233
|
// Server configuration
|
|
22
234
|
server: {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
apiPrefix: env.API_PREFIX, // Direto! (string)
|
|
26
|
-
cors: {
|
|
27
|
-
origins: env.CORS_ORIGINS, // Direto! (string[])
|
|
28
|
-
methods: env.get('CORS_METHODS', ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS']),
|
|
29
|
-
headers: env.get('CORS_HEADERS', ['Content-Type', 'Authorization']),
|
|
30
|
-
credentials: env.get('CORS_CREDENTIALS', false), // boolean casting
|
|
31
|
-
maxAge: env.get('CORS_MAX_AGE', 86400) // number casting
|
|
32
|
-
},
|
|
235
|
+
...serverConfig,
|
|
236
|
+
cors: corsConfig,
|
|
33
237
|
middleware: []
|
|
34
238
|
},
|
|
35
239
|
|
|
36
240
|
// Client configuration
|
|
37
241
|
client: {
|
|
38
|
-
|
|
39
|
-
proxy:
|
|
40
|
-
|
|
41
|
-
changeOrigin: env.get('PROXY_CHANGE_ORIGIN', true)
|
|
42
|
-
},
|
|
43
|
-
build: {
|
|
44
|
-
sourceMaps: env.get('CLIENT_SOURCEMAPS', helpers.isDevelopment()),
|
|
45
|
-
target: env.get('CLIENT_TARGET', 'esnext'),
|
|
46
|
-
outDir: env.get('CLIENT_OUTDIR', 'dist/client')
|
|
47
|
-
}
|
|
242
|
+
...clientConfig,
|
|
243
|
+
proxy: clientProxyConfig,
|
|
244
|
+
build: clientBuildConfig
|
|
48
245
|
},
|
|
49
246
|
|
|
50
247
|
// Build configuration
|
|
51
248
|
build: {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
optimization: {
|
|
55
|
-
treeshake: env.get('BUILD_TREESHAKE', helpers.isProduction()),
|
|
56
|
-
compress: env.get('BUILD_COMPRESS', helpers.isProduction()),
|
|
57
|
-
splitChunks: env.get('BUILD_SPLIT_CHUNKS', true),
|
|
58
|
-
bundleAnalyzer: env.get('BUILD_ANALYZER', helpers.isDevelopment())
|
|
59
|
-
},
|
|
60
|
-
sourceMaps: env.get('BUILD_SOURCEMAPS', !helpers.isProduction()),
|
|
61
|
-
clean: env.get('BUILD_CLEAN', true)
|
|
249
|
+
...buildConfig,
|
|
250
|
+
optimization: buildOptimizationConfig
|
|
62
251
|
},
|
|
63
252
|
|
|
64
253
|
// Plugin configuration
|
|
65
254
|
plugins: {
|
|
66
|
-
|
|
67
|
-
disabled: env.get('FLUXSTACK_PLUGINS_DISABLED', []),
|
|
255
|
+
...pluginsConfig,
|
|
68
256
|
config: {
|
|
69
|
-
// Plugin-specific configurations can be added here
|
|
70
257
|
logger: {
|
|
71
|
-
// Logger plugin config
|
|
258
|
+
// Logger plugin config handled by logging section
|
|
72
259
|
},
|
|
73
260
|
swagger: {
|
|
74
261
|
title: env.get('SWAGGER_TITLE', 'FluxStack API'),
|
|
@@ -81,95 +268,39 @@ export const config: FluxStackConfig = {
|
|
|
81
268
|
cacheMaxAge: env.get('STATIC_CACHE_MAX_AGE', 31536000), // 1 year
|
|
82
269
|
enableUploads: env.get('STATIC_ENABLE_UPLOADS', true),
|
|
83
270
|
enablePublic: env.get('STATIC_ENABLE_PUBLIC', true)
|
|
84
|
-
},
|
|
85
|
-
'crypto-auth': {
|
|
86
|
-
enabled: env.get('CRYPTO_AUTH_ENABLED', true),
|
|
87
|
-
sessionTimeout: env.get('CRYPTO_AUTH_SESSION_TIMEOUT', 1800000), // 30 minutos
|
|
88
|
-
maxTimeDrift: env.get('CRYPTO_AUTH_MAX_TIME_DRIFT', 300000), // 5 minutos
|
|
89
|
-
adminKeys: env.get('CRYPTO_AUTH_ADMIN_KEYS', []),
|
|
90
|
-
protectedRoutes: env.get('CRYPTO_AUTH_PROTECTED_ROUTES', ['/api/admin/*', '/api/protected/*']),
|
|
91
|
-
publicRoutes: env.get('CRYPTO_AUTH_PUBLIC_ROUTES', ['/api/auth/*', '/api/health', '/api/docs']),
|
|
92
|
-
enableMetrics: env.get('CRYPTO_AUTH_ENABLE_METRICS', true)
|
|
93
271
|
}
|
|
272
|
+
// ✅ crypto-auth manages its own configuration
|
|
273
|
+
// See: plugins/crypto-auth/config/index.ts
|
|
94
274
|
}
|
|
95
275
|
},
|
|
96
276
|
|
|
97
277
|
// Logging configuration
|
|
98
278
|
logging: {
|
|
99
|
-
|
|
100
|
-
format: env.get('LOG_FORMAT', helpers.isDevelopment() ? 'pretty' : 'json'),
|
|
279
|
+
...loggingConfig,
|
|
101
280
|
transports: [
|
|
102
281
|
{
|
|
103
282
|
type: 'console' as const,
|
|
104
|
-
level:
|
|
105
|
-
format:
|
|
283
|
+
level: loggingConfig.level,
|
|
284
|
+
format: loggingConfig.format
|
|
106
285
|
}
|
|
107
286
|
]
|
|
108
287
|
},
|
|
109
288
|
|
|
110
289
|
// Monitoring configuration
|
|
111
290
|
monitoring: {
|
|
112
|
-
|
|
113
|
-
metrics:
|
|
114
|
-
|
|
115
|
-
collectInterval: env.get('METRICS_INTERVAL', 5000), // number casting
|
|
116
|
-
httpMetrics: env.get('HTTP_METRICS', true),
|
|
117
|
-
systemMetrics: env.get('SYSTEM_METRICS', true),
|
|
118
|
-
customMetrics: env.get('CUSTOM_METRICS', false)
|
|
119
|
-
},
|
|
120
|
-
profiling: {
|
|
121
|
-
enabled: env.get('PROFILING_ENABLED', false),
|
|
122
|
-
sampleRate: env.get('PROFILING_SAMPLE_RATE', 0.1), // number casting
|
|
123
|
-
memoryProfiling: env.get('MEMORY_PROFILING', false),
|
|
124
|
-
cpuProfiling: env.get('CPU_PROFILING', false)
|
|
125
|
-
},
|
|
126
|
-
exporters: env.get('MONITORING_EXPORTERS', []) // array casting
|
|
291
|
+
...monitoringConfig,
|
|
292
|
+
metrics: monitoringMetricsConfig,
|
|
293
|
+
profiling: monitoringProfilingConfig
|
|
127
294
|
},
|
|
128
295
|
|
|
129
|
-
// Optional
|
|
130
|
-
...(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
port: env.DB_PORT, // Direto! (number)
|
|
135
|
-
database: env.DB_NAME, // Direto! (string)
|
|
136
|
-
user: env.DB_USER, // Direto! (string)
|
|
137
|
-
password: env.DB_PASSWORD, // Direto! (string)
|
|
138
|
-
ssl: env.DB_SSL, // Direto! (boolean)
|
|
139
|
-
poolSize: env.get('DB_POOL_SIZE', 10) // number casting
|
|
140
|
-
}
|
|
141
|
-
} : {}),
|
|
142
|
-
|
|
143
|
-
// Optional authentication configuration
|
|
144
|
-
...(env.has('JWT_SECRET') ? {
|
|
145
|
-
auth: {
|
|
146
|
-
secret: env.JWT_SECRET, // Direto! (string)
|
|
147
|
-
expiresIn: env.get('JWT_EXPIRES_IN', '24h'),
|
|
148
|
-
algorithm: env.get('JWT_ALGORITHM', 'HS256'),
|
|
149
|
-
issuer: env.get('JWT_ISSUER')
|
|
150
|
-
}
|
|
151
|
-
} : {}),
|
|
152
|
-
|
|
153
|
-
// Optional email configuration
|
|
154
|
-
...(env.has('SMTP_HOST') ? {
|
|
155
|
-
email: {
|
|
156
|
-
host: env.SMTP_HOST, // Direto! (string)
|
|
157
|
-
port: env.SMTP_PORT, // Direto! (number)
|
|
158
|
-
user: env.SMTP_USER, // Direto! (string)
|
|
159
|
-
password: env.SMTP_PASSWORD, // Direto! (string)
|
|
160
|
-
secure: env.SMTP_SECURE, // Direto! (boolean)
|
|
161
|
-
from: env.get('SMTP_FROM')
|
|
162
|
-
}
|
|
163
|
-
} : {}),
|
|
164
|
-
|
|
165
|
-
// Optional storage configuration
|
|
166
|
-
...(env.has('UPLOAD_PATH') || env.has('STORAGE_PROVIDER') ? {
|
|
296
|
+
// Optional configurations (only included if env vars are set)
|
|
297
|
+
...(databaseConfig ? { database: databaseConfig } : {}),
|
|
298
|
+
...(authConfig ? { auth: authConfig } : {}),
|
|
299
|
+
...(emailConfig ? { email: emailConfig } : {}),
|
|
300
|
+
...(storageConfig ? {
|
|
167
301
|
storage: {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
allowedTypes: env.get('ALLOWED_FILE_TYPES', []), // array casting
|
|
171
|
-
provider: env.get('STORAGE_PROVIDER', 'local'),
|
|
172
|
-
config: env.get('STORAGE_CONFIG', {}) // object casting
|
|
302
|
+
...storageConfig,
|
|
303
|
+
config: env.get('STORAGE_CONFIG', {})
|
|
173
304
|
}
|
|
174
305
|
} : {}),
|
|
175
306
|
|
|
@@ -192,6 +323,7 @@ export const config: FluxStackConfig = {
|
|
|
192
323
|
proxy: { target: 'http://localhost:3000' },
|
|
193
324
|
build: {
|
|
194
325
|
sourceMaps: true,
|
|
326
|
+
minify: false,
|
|
195
327
|
target: 'es2020',
|
|
196
328
|
outDir: 'dist'
|
|
197
329
|
}
|
|
@@ -200,12 +332,15 @@ export const config: FluxStackConfig = {
|
|
|
200
332
|
target: 'bun',
|
|
201
333
|
outDir: 'dist',
|
|
202
334
|
optimization: {
|
|
335
|
+
minify: false,
|
|
203
336
|
compress: false,
|
|
204
337
|
treeshake: false,
|
|
205
338
|
splitChunks: false,
|
|
206
339
|
bundleAnalyzer: false
|
|
207
340
|
},
|
|
208
341
|
sourceMaps: true,
|
|
342
|
+
minify: false,
|
|
343
|
+
treeshake: false,
|
|
209
344
|
clean: true
|
|
210
345
|
},
|
|
211
346
|
monitoring: {
|
|
@@ -243,6 +378,7 @@ export const config: FluxStackConfig = {
|
|
|
243
378
|
proxy: { target: 'http://localhost:3000' },
|
|
244
379
|
build: {
|
|
245
380
|
sourceMaps: false,
|
|
381
|
+
minify: true,
|
|
246
382
|
target: 'es2020',
|
|
247
383
|
outDir: 'dist'
|
|
248
384
|
}
|
|
@@ -251,12 +387,15 @@ export const config: FluxStackConfig = {
|
|
|
251
387
|
target: 'bun',
|
|
252
388
|
outDir: 'dist',
|
|
253
389
|
optimization: {
|
|
390
|
+
minify: true,
|
|
254
391
|
treeshake: false,
|
|
255
392
|
compress: false,
|
|
256
393
|
splitChunks: false,
|
|
257
394
|
bundleAnalyzer: false
|
|
258
395
|
},
|
|
259
396
|
sourceMaps: false,
|
|
397
|
+
minify: true,
|
|
398
|
+
treeshake: false,
|
|
260
399
|
clean: true
|
|
261
400
|
},
|
|
262
401
|
monitoring: {
|
|
@@ -300,7 +439,7 @@ export const config: FluxStackConfig = {
|
|
|
300
439
|
client: {
|
|
301
440
|
port: 0, // Use random available port
|
|
302
441
|
proxy: { target: 'http://localhost:3000' },
|
|
303
|
-
build: { sourceMaps: true, target: 'es2020', outDir: 'dist' }
|
|
442
|
+
build: { sourceMaps: true, minify: false, target: 'es2020', outDir: 'dist' }
|
|
304
443
|
},
|
|
305
444
|
monitoring: {
|
|
306
445
|
enabled: false,
|