create-fluxstack 1.0.21 → 1.1.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 (31) hide show
  1. package/app/server/live/register-components.ts +6 -26
  2. package/core/build/bundler.ts +53 -5
  3. package/core/build/flux-plugins-generator.ts +315 -0
  4. package/core/build/index.ts +1 -3
  5. package/core/build/live-components-generator.ts +231 -0
  6. package/core/build/optimizer.ts +2 -54
  7. package/core/cli/index.ts +2 -1
  8. package/core/config/env.ts +3 -1
  9. package/core/config/schema.ts +0 -3
  10. package/core/framework/server.ts +33 -1
  11. package/core/plugins/built-in/static/index.ts +24 -10
  12. package/core/plugins/built-in/vite/index.ts +92 -56
  13. package/core/plugins/manager.ts +51 -8
  14. package/core/utils/helpers.ts +9 -3
  15. package/fluxstack.config.ts +4 -10
  16. package/package.json +4 -3
  17. package/plugins/crypto-auth/README.md +238 -0
  18. package/plugins/crypto-auth/client/CryptoAuthClient.ts +325 -0
  19. package/plugins/crypto-auth/client/components/AuthProvider.tsx +190 -0
  20. package/plugins/crypto-auth/client/components/LoginButton.tsx +155 -0
  21. package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +109 -0
  22. package/plugins/crypto-auth/client/components/SessionInfo.tsx +242 -0
  23. package/plugins/crypto-auth/client/components/index.ts +15 -0
  24. package/plugins/crypto-auth/client/index.ts +12 -0
  25. package/plugins/crypto-auth/index.ts +230 -0
  26. package/plugins/crypto-auth/package.json +65 -0
  27. package/plugins/crypto-auth/plugin.json +29 -0
  28. package/plugins/crypto-auth/server/AuthMiddleware.ts +237 -0
  29. package/plugins/crypto-auth/server/CryptoAuthService.ts +293 -0
  30. package/plugins/crypto-auth/server/index.ts +9 -0
  31. package/vite.config.ts +16 -0
@@ -12,7 +12,7 @@ export const vitePlugin: Plugin = {
12
12
  category: "development",
13
13
  tags: ["vite", "development", "hot-reload"],
14
14
  dependencies: [], // No dependencies
15
-
15
+
16
16
  configSchema: {
17
17
  type: "object",
18
18
  properties: {
@@ -51,14 +51,14 @@ export const vitePlugin: Plugin = {
51
51
  description: "Paths to proxy to Vite (defaults to all non-API paths)"
52
52
  },
53
53
  excludePaths: {
54
- type: "array",
54
+ type: "array",
55
55
  items: { type: "string" },
56
56
  description: "Paths to exclude from Vite proxying"
57
57
  }
58
58
  },
59
59
  additionalProperties: false
60
60
  },
61
-
61
+
62
62
  defaultConfig: {
63
63
  enabled: true,
64
64
  port: 5173,
@@ -72,17 +72,17 @@ export const vitePlugin: Plugin = {
72
72
 
73
73
  setup: async (context: PluginContext) => {
74
74
  const config = getPluginConfig(context)
75
-
75
+
76
76
  if (!config.enabled || !context.config.client) {
77
77
  context.logger.info('Vite plugin disabled or no client configuration found')
78
78
  return
79
79
  }
80
-
80
+
81
81
  const vitePort = config.port || context.config.client.port || 5173
82
82
  const viteHost = config.host || "localhost"
83
-
83
+
84
84
  context.logger.info(`🎨 Starting Vite dev server programmatically on ${viteHost}:${vitePort}`)
85
-
85
+
86
86
  try {
87
87
  // Start Vite dev server programmatically
88
88
  viteServer = await createServer({
@@ -93,21 +93,21 @@ export const vitePlugin: Plugin = {
93
93
  host: viteHost
94
94
  }
95
95
  })
96
-
96
+
97
97
  await viteServer.listen()
98
98
  viteServer.printUrls()
99
-
99
+
100
100
  context.logger.info(`✅ Vite server started successfully on ${viteHost}:${vitePort}`)
101
101
  context.logger.info('🔄 Hot reload coordination active - Zero órfãos!')
102
-
103
- // Store Vite config in context for later use
104
- ;(context as any).viteConfig = {
105
- port: vitePort,
106
- host: viteHost,
107
- ...config,
108
- server: viteServer
109
- }
110
-
102
+
103
+ // Store Vite config in context for later use
104
+ ; (context as any).viteConfig = {
105
+ port: vitePort,
106
+ host: viteHost,
107
+ ...config,
108
+ server: viteServer
109
+ }
110
+
111
111
  // Setup cleanup on process exit
112
112
  const cleanup = async () => {
113
113
  if (viteServer) {
@@ -116,21 +116,21 @@ export const vitePlugin: Plugin = {
116
116
  viteServer = null
117
117
  }
118
118
  }
119
-
119
+
120
120
  process.on('SIGINT', cleanup)
121
121
  process.on('SIGTERM', cleanup)
122
122
  process.on('exit', cleanup)
123
-
123
+
124
124
  } catch (error) {
125
125
  context.logger.error('❌ Failed to start Vite server programmatically:', error)
126
126
  context.logger.info('⚠️ Falling back to monitoring mode...')
127
-
128
- // Fallback to monitoring if programmatic start fails
129
- ;(context as any).viteConfig = {
130
- port: vitePort,
131
- host: viteHost,
132
- ...config
133
- }
127
+
128
+ // Fallback to monitoring if programmatic start fails
129
+ ; (context as any).viteConfig = {
130
+ port: vitePort,
131
+ host: viteHost,
132
+ ...config
133
+ }
134
134
  monitorVite(context, viteHost, vitePort, config)
135
135
  }
136
136
  },
@@ -138,45 +138,81 @@ export const vitePlugin: Plugin = {
138
138
  onServerStart: async (context: PluginContext) => {
139
139
  const config = getPluginConfig(context)
140
140
  const viteConfig = (context as any).viteConfig
141
-
141
+
142
142
  if (config.enabled && viteConfig) {
143
143
  context.logger.info(`Vite integration active - monitoring ${viteConfig.host}:${viteConfig.port}`)
144
144
  }
145
145
  },
146
146
 
147
147
  onBeforeRoute: async (requestContext: RequestContext) => {
148
- // Skip API routes, swagger, and ALL Vite internal routes
149
- if (requestContext.path.startsWith("/api") ||
150
- requestContext.path.startsWith("/swagger") ||
151
- requestContext.path.startsWith("/@") || // All Vite internal routes (/@vite/, /@fs/, /@react-refresh, etc.)
152
- requestContext.path.startsWith("/__vite") || // Vite HMR and dev routes
153
- requestContext.path.startsWith("/node_modules") || // Direct node_modules access
154
- requestContext.path.includes("/.vite/") || // Vite cache and deps
155
- requestContext.path.endsWith(".js.map") || // Source maps
156
- requestContext.path.endsWith(".css.map")) { // CSS source maps
148
+ // Skip API routes and swagger - let them be handled by backend
149
+ if (requestContext.path.startsWith("/api") || requestContext.path.startsWith("/swagger")) {
157
150
  return
158
151
  }
159
-
152
+
153
+ // For Vite internal routes, proxy directly to Vite server
154
+ if (requestContext.path.startsWith("/@") || // All Vite internal routes (/@vite/, /@fs/, /@react-refresh, etc.)
155
+ requestContext.path.startsWith("/__vite") || // Vite HMR and dev routes
156
+ requestContext.path.startsWith("/node_modules") || // Direct node_modules access
157
+ requestContext.path.includes("/.vite/") || // Vite cache and deps
158
+ requestContext.path.endsWith(".js.map") || // Source maps
159
+ requestContext.path.endsWith(".css.map")) { // CSS source maps
160
+
161
+ // Use fixed configuration for Vite proxy
162
+ const viteHost = "localhost"
163
+ const vitePort = 5173
164
+
165
+ try {
166
+ const url = new URL(requestContext.request.url)
167
+ const viteUrl = `http://${viteHost}:${vitePort}${requestContext.path}${url.search}`
168
+
169
+ // Forward request to Vite
170
+ const response = await fetch(viteUrl, {
171
+ method: requestContext.method,
172
+ headers: requestContext.headers,
173
+ body: requestContext.method !== 'GET' && requestContext.method !== 'HEAD' ? requestContext.request.body : undefined
174
+ })
175
+
176
+ // Return the Vite response
177
+ const body = await response.arrayBuffer()
178
+
179
+ requestContext.handled = true
180
+ requestContext.response = new Response(body, {
181
+ status: response.status,
182
+ statusText: response.statusText,
183
+ headers: response.headers
184
+ })
185
+
186
+ } catch (viteError) {
187
+ // If Vite fails, let the request continue to normal routing (will become 404)
188
+ // Only log if explicitly enabled for debugging
189
+ if (process.env.ENABLE_VITE_PROXY_LOGS === 'true') {
190
+ console.warn(`Vite proxy error: ${viteError}`)
191
+ }
192
+ }
193
+ return
194
+ }
195
+
160
196
  // Use fixed configuration for simplicity - Vite should be running on port 5173
161
197
  const viteHost = "localhost"
162
198
  const vitePort = 5173
163
-
199
+
164
200
  try {
165
201
  const url = new URL(requestContext.request.url)
166
202
  const viteUrl = `http://${viteHost}:${vitePort}${requestContext.path}${url.search}`
167
-
203
+
168
204
  // Forward request to Vite
169
205
  const response = await fetch(viteUrl, {
170
206
  method: requestContext.method,
171
207
  headers: requestContext.headers,
172
208
  body: requestContext.method !== 'GET' && requestContext.method !== 'HEAD' ? requestContext.request.body : undefined
173
209
  })
174
-
210
+
175
211
  // If Vite responds successfully, handle the request
176
212
  if (response.ok || response.status < 500) {
177
213
  // Return a proper Response object with all headers and status
178
214
  const body = await response.arrayBuffer()
179
-
215
+
180
216
  requestContext.handled = true
181
217
  requestContext.response = new Response(body, {
182
218
  status: response.status,
@@ -184,7 +220,7 @@ export const vitePlugin: Plugin = {
184
220
  headers: response.headers
185
221
  })
186
222
  }
187
-
223
+
188
224
  } catch (viteError) {
189
225
  // If Vite fails, let the request continue to normal routing (will become 404)
190
226
  // Only log if explicitly enabled for debugging
@@ -203,16 +239,16 @@ function getPluginConfig(context: PluginContext) {
203
239
 
204
240
  // Monitor Vite server status with automatic port detection
205
241
  async function monitorVite(
206
- context: PluginContext,
207
- host: string,
208
- initialPort: number,
242
+ context: PluginContext,
243
+ host: string,
244
+ initialPort: number,
209
245
  config: any
210
246
  ) {
211
247
  let retries = 0
212
248
  let isConnected = false
213
249
  let actualPort = initialPort
214
250
  let portDetected = false
215
-
251
+
216
252
  const checkVite = async () => {
217
253
  try {
218
254
  // If we haven't found the correct port yet, try to detect it
@@ -223,13 +259,13 @@ async function monitorVite(
223
259
  portDetected = true
224
260
  // Update the context with the detected port
225
261
  if ((context as any).viteConfig) {
226
- ;(context as any).viteConfig.port = actualPort
262
+ ; (context as any).viteConfig.port = actualPort
227
263
  }
228
264
  }
229
265
  }
230
-
266
+
231
267
  const isRunning = await checkViteRunning(host, actualPort, config.timeout)
232
-
268
+
233
269
  if (isRunning && !isConnected) {
234
270
  isConnected = true
235
271
  retries = 0
@@ -262,11 +298,11 @@ async function monitorVite(
262
298
  context.logger.error('Error checking Vite server status', { error })
263
299
  }
264
300
  }
265
-
301
+
266
302
  // Continue monitoring
267
303
  setTimeout(checkVite, config.checkInterval)
268
304
  }
269
-
305
+
270
306
  // Start monitoring after a brief delay
271
307
  setTimeout(checkVite, 1000)
272
308
  }
@@ -285,7 +321,7 @@ async function detectVitePort(host: string, startPort: number): Promise<number |
285
321
  3000, // Sometimes Vite might use this
286
322
  4173 // Another common alternative
287
323
  ]
288
-
324
+
289
325
  for (const port of portsToTry) {
290
326
  try {
291
327
  const isRunning = await checkViteRunning(host, port, 1000)
@@ -296,7 +332,7 @@ async function detectVitePort(host: string, startPort: number): Promise<number |
296
332
  // Continue trying other ports
297
333
  }
298
334
  }
299
-
335
+
300
336
  return null
301
337
  }
302
338
 
@@ -305,12 +341,12 @@ async function checkViteRunning(host: string, port: number, timeout: number = 10
305
341
  try {
306
342
  const controller = new AbortController()
307
343
  const timeoutId = setTimeout(() => controller.abort(), timeout)
308
-
344
+
309
345
  const response = await fetch(`http://${host}:${port}`, {
310
346
  signal: controller.signal,
311
347
  method: 'HEAD' // Use HEAD to minimize data transfer
312
348
  })
313
-
349
+
314
350
  clearTimeout(timeoutId)
315
351
  return response.status >= 200 && response.status < 500
316
352
  } catch (error) {
@@ -64,20 +64,35 @@ export class PluginManager extends EventEmitter {
64
64
 
65
65
  try {
66
66
  // Discover and load plugins
67
+ this.logger.debug('Starting plugin discovery...')
67
68
  await this.discoverPlugins()
69
+ this.logger.debug('Plugin discovery completed')
68
70
 
69
71
  // Setup plugin contexts
72
+ this.logger.debug('Setting up plugin contexts...')
70
73
  this.setupPluginContexts()
74
+ this.logger.debug('Plugin contexts setup completed')
71
75
 
72
76
  // Execute setup hooks
77
+ this.logger.debug('Executing setup hooks...')
73
78
  await this.executeHook('setup')
79
+ this.logger.debug('Setup hooks execution completed')
74
80
 
75
81
  this.initialized = true
82
+ const stats = this.registry.getStats()
76
83
  this.logger.info('Plugin manager initialized successfully', {
77
- totalPlugins: this.registry.getStats().totalPlugins
84
+ totalPlugins: stats.totalPlugins,
85
+ enabledPlugins: stats.enabledPlugins,
86
+ loadOrder: stats.loadOrder
78
87
  })
79
88
  } catch (error) {
80
- this.logger.error('Failed to initialize plugin manager', { error })
89
+ this.logger.error('Failed to initialize plugin manager', {
90
+ error: error instanceof Error ? {
91
+ message: error.message,
92
+ stack: error.stack,
93
+ name: error.name
94
+ } : error
95
+ })
81
96
  throw error
82
97
  }
83
98
  }
@@ -396,12 +411,40 @@ export class PluginManager extends EventEmitter {
396
411
  */
397
412
  private async discoverPlugins(): Promise<void> {
398
413
  try {
399
- this.logger.info('Discovering external plugins in directory: plugins')
400
- const results = await this.registry.discoverPlugins({
401
- directories: ['plugins'],
402
- includeBuiltIn: false,
403
- includeExternal: true
414
+ // Load built-in plugins first (handled by core system)
415
+ this.logger.info('Loading built-in plugins...')
416
+ const builtInResults = await this.registry.discoverPlugins({
417
+ directories: [],
418
+ includeBuiltIn: true,
419
+ includeExternal: false
404
420
  })
421
+
422
+ // Try to use auto-generated registry for external plugins (if available from build)
423
+ let externalResults: any[] = []
424
+ try {
425
+ const autoRegistryModule = await import('./auto-registry')
426
+ if (autoRegistryModule.discoveredPlugins && autoRegistryModule.registerDiscoveredPlugins) {
427
+ this.logger.info('🚀 Using auto-generated external plugins registry')
428
+ await autoRegistryModule.registerDiscoveredPlugins(this.registry)
429
+ externalResults = autoRegistryModule.discoveredPlugins.map((plugin: any) => ({
430
+ success: true,
431
+ plugin
432
+ }))
433
+ }
434
+ } catch (error) {
435
+ this.logger.debug('Auto-generated external plugins registry not found, falling back to discovery', { error: error.message })
436
+
437
+ // Fallback to runtime discovery for external plugins
438
+ this.logger.info('Discovering external plugins in directory: plugins')
439
+ externalResults = await this.registry.discoverPlugins({
440
+ directories: ['plugins'],
441
+ includeBuiltIn: false,
442
+ includeExternal: true
443
+ })
444
+ }
445
+
446
+ // Combine results
447
+ const results = [...builtInResults, ...externalResults]
405
448
 
406
449
  let loaded = 0
407
450
  let failed = 0
@@ -448,7 +491,7 @@ export class PluginManager extends EventEmitter {
448
491
 
449
492
  const context: PluginContext = {
450
493
  config: this.config,
451
- logger: this.logger,
494
+ logger: this.logger.child ? this.logger.child({ plugin: plugin.name }) : this.logger,
452
495
  app: this.app,
453
496
  utils: createPluginUtils(this.logger),
454
497
  registry: this.registry
@@ -87,15 +87,21 @@ export const throttle = <T extends (...args: any[]) => any>(
87
87
  }
88
88
 
89
89
  export const isProduction = (): boolean => {
90
- return process.env.NODE_ENV === 'production'
90
+ // Import here to avoid circular dependency
91
+ const { env } = require('./env-runtime-v2')
92
+ return env.NODE_ENV === 'production'
91
93
  }
92
94
 
93
95
  export const isDevelopment = (): boolean => {
94
- return process.env.NODE_ENV === 'development' || !process.env.NODE_ENV
96
+ // Import here to avoid circular dependency
97
+ const { env } = require('./env-runtime-v2')
98
+ return env.NODE_ENV === 'development' || !env.NODE_ENV
95
99
  }
96
100
 
97
101
  export const isTest = (): boolean => {
98
- return process.env.NODE_ENV === 'test'
102
+ // Import here to avoid circular dependency
103
+ const { env } = require('./env-runtime-v2')
104
+ return env.NODE_ENV === 'test'
99
105
  }
100
106
 
101
107
  export const deepMerge = <T extends Record<string, any>>(target: T, source: Partial<T>): T => {
@@ -42,7 +42,6 @@ export const config: FluxStackConfig = {
42
42
  },
43
43
  build: {
44
44
  sourceMaps: env.get('CLIENT_SOURCEMAPS', helpers.isDevelopment()),
45
- minify: env.get('CLIENT_MINIFY', helpers.isProduction()),
46
45
  target: env.get('CLIENT_TARGET', 'esnext'),
47
46
  outDir: env.get('CLIENT_OUTDIR', 'dist/client')
48
47
  }
@@ -53,7 +52,6 @@ export const config: FluxStackConfig = {
53
52
  target: env.get('BUILD_TARGET', 'bun'), // string casting
54
53
  outDir: env.get('BUILD_OUTDIR', 'dist'), // string
55
54
  optimization: {
56
- minify: env.get('BUILD_MINIFY', helpers.isProduction()),
57
55
  treeshake: env.get('BUILD_TREESHAKE', helpers.isProduction()),
58
56
  compress: env.get('BUILD_COMPRESS', helpers.isProduction()),
59
57
  splitChunks: env.get('BUILD_SPLIT_CHUNKS', true),
@@ -193,7 +191,6 @@ export const config: FluxStackConfig = {
193
191
  port: 5173,
194
192
  proxy: { target: 'http://localhost:3000' },
195
193
  build: {
196
- minify: false,
197
194
  sourceMaps: true,
198
195
  target: 'es2020',
199
196
  outDir: 'dist'
@@ -203,7 +200,6 @@ export const config: FluxStackConfig = {
203
200
  target: 'bun',
204
201
  outDir: 'dist',
205
202
  optimization: {
206
- minify: false,
207
203
  compress: false,
208
204
  treeshake: false,
209
205
  splitChunks: false,
@@ -246,7 +242,6 @@ export const config: FluxStackConfig = {
246
242
  port: 5173,
247
243
  proxy: { target: 'http://localhost:3000' },
248
244
  build: {
249
- minify: true,
250
245
  sourceMaps: false,
251
246
  target: 'es2020',
252
247
  outDir: 'dist'
@@ -256,10 +251,9 @@ export const config: FluxStackConfig = {
256
251
  target: 'bun',
257
252
  outDir: 'dist',
258
253
  optimization: {
259
- minify: true,
260
- treeshake: true,
261
- compress: true,
262
- splitChunks: true,
254
+ treeshake: false,
255
+ compress: false,
256
+ splitChunks: false,
263
257
  bundleAnalyzer: false
264
258
  },
265
259
  sourceMaps: false,
@@ -306,7 +300,7 @@ export const config: FluxStackConfig = {
306
300
  client: {
307
301
  port: 0, // Use random available port
308
302
  proxy: { target: 'http://localhost:3000' },
309
- build: { sourceMaps: true, minify: false, target: 'es2020', outDir: 'dist' }
303
+ build: { sourceMaps: true, target: 'es2020', outDir: 'dist' }
310
304
  },
311
305
  monitoring: {
312
306
  enabled: false,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-fluxstack",
3
- "version": "1.0.21",
4
- "description": "⚡ Modern full-stack TypeScript framework with Elysia + React + Bun",
3
+ "version": "1.1.0",
4
+ "description": "⚡ Revolutionary full-stack TypeScript framework with Temporal Bridge Auto-Discovery, Elysia + React + Bun",
5
5
  "keywords": [
6
6
  "framework",
7
7
  "full-stack",
@@ -29,7 +29,7 @@
29
29
  "dev:backend": "bun run core/cli/index.ts backend",
30
30
  "dev:coordinated": "concurrently --prefix {name} --names BACKEND,VITE --prefix-colors blue,green --kill-others-on-fail \"bun --watch app/server/index.ts\" \"vite --config vite.config.ts\"",
31
31
  "dev:clean": "bun run run-clean.ts",
32
- "build": "bun run core/cli/index.ts build",
32
+ "build": "cross-env NODE_ENV=production bun run core/cli/index.ts build",
33
33
  "build:frontend": "vite build --config vite.config.ts --emptyOutDir",
34
34
  "build:backend": "bun run core/cli/index.ts build:backend",
35
35
  "start": "bun run core/cli/index.ts start",
@@ -70,6 +70,7 @@
70
70
  "@vitest/coverage-v8": "^3.2.4",
71
71
  "@vitest/ui": "^3.2.4",
72
72
  "concurrently": "^9.2.0",
73
+ "cross-env": "^10.1.0",
73
74
  "eslint": "^9.30.1",
74
75
  "eslint-plugin-react-hooks": "^5.2.0",
75
76
  "eslint-plugin-react-refresh": "^0.4.20",