create-fluxstack 1.18.0 → 1.19.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 (54) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/app/client/src/App.tsx +7 -7
  3. package/app/client/src/components/AppLayout.tsx +60 -23
  4. package/app/client/src/components/ColorWheel.tsx +195 -0
  5. package/app/client/src/components/DemoPage.tsx +5 -3
  6. package/app/client/src/components/LiveUploadWidget.tsx +1 -1
  7. package/app/client/src/components/ThemePicker.tsx +307 -0
  8. package/app/client/src/config/theme.config.ts +127 -0
  9. package/app/client/src/hooks/useThemeClock.ts +66 -0
  10. package/app/client/src/index.css +193 -0
  11. package/app/client/src/lib/theme-clock.ts +201 -0
  12. package/app/client/src/live/AuthDemo.tsx +9 -9
  13. package/app/client/src/live/CounterDemo.tsx +10 -10
  14. package/app/client/src/live/FormDemo.tsx +8 -8
  15. package/app/client/src/live/PingPongDemo.tsx +10 -10
  16. package/app/client/src/live/RoomChatDemo.tsx +10 -10
  17. package/app/client/src/live/SharedCounterDemo.tsx +5 -5
  18. package/app/client/src/pages/ApiTestPage.tsx +5 -5
  19. package/app/client/src/pages/HomePage.tsx +12 -12
  20. package/app/server/index.ts +8 -0
  21. package/app/server/live/auto-generated-components.ts +1 -1
  22. package/app/server/live/rooms/ChatRoom.ts +13 -8
  23. package/app/server/routes/index.ts +20 -10
  24. package/core/build/index.ts +1 -1
  25. package/core/cli/command-registry.ts +1 -1
  26. package/core/cli/commands/build.ts +25 -6
  27. package/core/cli/commands/plugin-deps.ts +1 -2
  28. package/core/cli/generators/plugin.ts +433 -581
  29. package/core/framework/server.ts +34 -8
  30. package/core/index.ts +6 -5
  31. package/core/plugins/index.ts +71 -199
  32. package/core/plugins/types.ts +76 -461
  33. package/core/server/index.ts +1 -1
  34. package/core/utils/logger/startup-banner.ts +26 -4
  35. package/core/utils/version.ts +6 -6
  36. package/create-fluxstack.ts +216 -107
  37. package/package.json +108 -107
  38. package/tsconfig.json +2 -1
  39. package/app/client/.live-stubs/LiveAdminPanel.js +0 -15
  40. package/app/client/.live-stubs/LiveCounter.js +0 -9
  41. package/app/client/.live-stubs/LiveForm.js +0 -11
  42. package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
  43. package/app/client/.live-stubs/LivePingPong.js +0 -10
  44. package/app/client/.live-stubs/LiveRoomChat.js +0 -11
  45. package/app/client/.live-stubs/LiveSharedCounter.js +0 -10
  46. package/app/client/.live-stubs/LiveUpload.js +0 -15
  47. package/core/plugins/config.ts +0 -356
  48. package/core/plugins/dependency-manager.ts +0 -481
  49. package/core/plugins/discovery.ts +0 -379
  50. package/core/plugins/executor.ts +0 -353
  51. package/core/plugins/manager.ts +0 -645
  52. package/core/plugins/module-resolver.ts +0 -227
  53. package/core/plugins/registry.ts +0 -913
  54. package/vitest.config.live.ts +0 -69
@@ -5,13 +5,13 @@ export function HomePage({ apiStatus }: { apiStatus: 'checking' | 'online' | 'of
5
5
  <div className="flex flex-col items-center justify-center min-h-[calc(100vh-72px)] px-4 sm:px-6 py-12 text-center relative overflow-hidden">
6
6
 
7
7
  {/* Background glow */}
8
- <div className="absolute top-1/4 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[400px] h-[400px] bg-purple-500/10 rounded-full blur-[120px] pointer-events-none" />
8
+ <div className="absolute top-1/4 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[400px] h-[400px] bg-theme-accent rounded-full blur-[120px] pointer-events-none" />
9
9
 
10
10
  <div className="relative z-10 flex flex-col items-center w-full max-w-3xl">
11
11
 
12
12
  {/* Icon */}
13
13
  <div className="relative mb-5">
14
- <div className="absolute inset-0 bg-purple-500/20 rounded-full blur-2xl animate-pulse-slow" />
14
+ <div className="absolute inset-0 bg-theme-muted rounded-full blur-2xl animate-pulse-slow" />
15
15
  <img
16
16
  src={FluxStack}
17
17
  alt="FluxStack"
@@ -20,17 +20,17 @@ export function HomePage({ apiStatus }: { apiStatus: 'checking' | 'online' | 'of
20
20
  </div>
21
21
 
22
22
  {/* Title */}
23
- <h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-extrabold mb-3 bg-gradient-to-r from-cyan-400 via-purple-400 to-pink-400 bg-clip-text text-transparent tracking-tight leading-none">
23
+ <h1 className="text-4xl sm:text-5xl md:text-6xl lg:text-7xl font-extrabold mb-3 bg-theme-gradient bg-clip-text text-transparent tracking-tight leading-none">
24
24
  FluxStack
25
25
  </h1>
26
26
 
27
27
  {/* Subtitle */}
28
28
  <p className="text-sm sm:text-base md:text-lg text-gray-400 mb-6 leading-relaxed">
29
- <span className="text-purple-400 font-semibold">Bun</span>
29
+ <span className="text-theme font-semibold">Bun</span>
30
30
  {' + '}
31
- <span className="text-indigo-400 font-semibold">Elysia</span>
31
+ <span className="text-theme-secondary font-semibold">Elysia</span>
32
32
  {' + '}
33
- <span className="text-cyan-400 font-semibold">React</span>
33
+ <span className="text-theme-secondary font-semibold">React</span>
34
34
  {' = '}
35
35
  <span className="text-white font-semibold">FluxStack</span>
36
36
  </p>
@@ -53,24 +53,24 @@ export function HomePage({ apiStatus }: { apiStatus: 'checking' | 'online' | 'of
53
53
 
54
54
  {/* Feature cards */}
55
55
  <div className="grid grid-cols-1 sm:grid-cols-3 gap-3 sm:gap-4 w-full mb-12">
56
- <div className="group bg-white/[0.03] border border-white/[0.06] rounded-xl p-4 sm:p-5 hover:bg-white/[0.06] hover:border-purple-500/20 transition-all duration-300">
57
- <div className="w-8 h-8 rounded-lg bg-purple-500/10 flex items-center justify-center mb-3 group-hover:bg-purple-500/20 transition-colors">
56
+ <div className="group bg-white/[0.03] border border-white/[0.06] rounded-xl p-4 sm:p-5 hover:bg-white/[0.06] hover:border-theme transition-all duration-300">
57
+ <div className="w-8 h-8 rounded-lg bg-theme-accent flex items-center justify-center mb-3 group-hover:bg-theme-muted transition-colors">
58
58
  <span className="text-sm">⚡</span>
59
59
  </div>
60
60
  <h3 className="text-xs sm:text-sm font-semibold text-white mb-1 text-left">Ultra Rápido</h3>
61
61
  <p className="text-gray-500 text-[11px] sm:text-xs text-left leading-relaxed">Bun runtime com performance 3x superior ao Node.js</p>
62
62
  </div>
63
63
 
64
- <div className="group bg-white/[0.03] border border-white/[0.06] rounded-xl p-4 sm:p-5 hover:bg-white/[0.06] hover:border-indigo-500/20 transition-all duration-300">
65
- <div className="w-8 h-8 rounded-lg bg-indigo-500/10 flex items-center justify-center mb-3 group-hover:bg-indigo-500/20 transition-colors">
64
+ <div className="group bg-white/[0.03] border border-white/[0.06] rounded-xl p-4 sm:p-5 hover:bg-white/[0.06] hover:border-theme transition-all duration-300">
65
+ <div className="w-8 h-8 rounded-lg bg-theme-accent flex items-center justify-center mb-3 group-hover:bg-theme-muted transition-colors">
66
66
  <span className="text-sm">🔒</span>
67
67
  </div>
68
68
  <h3 className="text-xs sm:text-sm font-semibold text-white mb-1 text-left">Type Safe</h3>
69
69
  <p className="text-gray-500 text-[11px] sm:text-xs text-left leading-relaxed">Eden Treaty com inferência end-to-end automática</p>
70
70
  </div>
71
71
 
72
- <div className="group bg-white/[0.03] border border-white/[0.06] rounded-xl p-4 sm:p-5 hover:bg-white/[0.06] hover:border-cyan-500/20 transition-all duration-300">
73
- <div className="w-8 h-8 rounded-lg bg-cyan-500/10 flex items-center justify-center mb-3 group-hover:bg-cyan-500/20 transition-colors">
72
+ <div className="group bg-white/[0.03] border border-white/[0.06] rounded-xl p-4 sm:p-5 hover:bg-white/[0.06] hover:border-theme transition-all duration-300">
73
+ <div className="w-8 h-8 rounded-lg bg-theme-accent flex items-center justify-center mb-3 group-hover:bg-theme-muted transition-colors">
74
74
  <span className="text-sm">🔥</span>
75
75
  </div>
76
76
  <h3 className="text-xs sm:text-sm font-semibold text-white mb-1 text-left">Live Components</h3>
@@ -17,6 +17,13 @@ import { liveComponentsPlugin, registerAuthProvider } from "@core/server/live"
17
17
  import { appInstance } from "@server/app"
18
18
  import { appConfig } from "@config"
19
19
 
20
+ // 🔒 External plugins — registered explicitly via .use() so the bundler
21
+ // includes them statically. Auto-discovery via node_modules/ was removed
22
+ // in @fluxstack/plugin-kit@0.4.0 because it broke silently in production
23
+ // bundles (dist/node_modules/ does not exist). Every plugin the app
24
+ // wants to enable must be imported + `.use()`-d here.
25
+ import { csrfProtectionPlugin } from "@fluxstack/plugin-csrf-protection"
26
+
20
27
  // 🔒 Auth provider para Live Components
21
28
  import { DevAuthProvider } from "./auth/DevAuthProvider"
22
29
 
@@ -33,6 +40,7 @@ initAuth()
33
40
  const framework = new FluxStackFramework()
34
41
  .use(swaggerPlugin)
35
42
  .use(liveComponentsPlugin)
43
+ .use(csrfProtectionPlugin)
36
44
 
37
45
  // Vite apenas em full-stack
38
46
  if (appConfig.mode !== 'backend-only') {
@@ -1,6 +1,6 @@
1
1
  // Auto-generated Live Components Registration
2
2
  // Generated by @fluxstack/live — DO NOT EDIT MANUALLY
3
- // Generated at: 2026-04-09T02:31:46.153Z
3
+ // Generated at: 2026-04-11T19:00:17.642Z
4
4
 
5
5
  import { LiveAdminPanel } from "./LiveAdminPanel"
6
6
  import { LiveCounter } from "./LiveCounter"
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { LiveRoom } from '@fluxstack/live'
4
4
  import type { RoomJoinContext, RoomLeaveContext } from '@fluxstack/live'
5
- import { createHash, timingSafeEqual } from 'crypto'
5
+ import { createHash, randomBytes, timingSafeEqual } from 'crypto'
6
6
 
7
7
  export interface ChatMessage {
8
8
  id: string
@@ -33,15 +33,20 @@ export class ChatRoom extends LiveRoom<ChatState, ChatMeta, ChatEvents> {
33
33
  static defaultMeta: ChatMeta = { password: null, createdBy: null }
34
34
  static $options = { maxMembers: 100 }
35
35
 
36
- /** Hash a password using SHA-256. */
36
+ /** Hash a password using SHA-256 with a random salt. Returns "salt:hash". */
37
37
  private static hashPassword(password: string): string {
38
- return createHash('sha256').update(password).digest('hex')
38
+ const salt = randomBytes(16).toString('hex')
39
+ const hash = createHash('sha256').update(salt + password).digest('hex')
40
+ return salt + ':' + hash
39
41
  }
40
42
 
41
- /** Constant-time comparison of two hex strings. */
42
- private static safeCompare(a: string, b: string): boolean {
43
- const bufA = Buffer.from(a, 'hex')
44
- const bufB = Buffer.from(b, 'hex')
43
+ /** Verify a password against a stored "salt:hash" string using constant-time comparison. */
44
+ private static verifyPassword(password: string, stored: string): boolean {
45
+ const [salt, hash] = stored.split(':')
46
+ if (!salt || !hash) return false
47
+ const computed = createHash('sha256').update(salt + password).digest('hex')
48
+ const bufA = Buffer.from(computed, 'hex')
49
+ const bufB = Buffer.from(hash, 'hex')
45
50
  if (bufA.length !== bufB.length) return false
46
51
  return timingSafeEqual(bufA, bufB)
47
52
  }
@@ -56,7 +61,7 @@ export class ChatRoom extends LiveRoom<ChatState, ChatMeta, ChatEvents> {
56
61
  // Validate password if room is protected
57
62
  if (this.meta.password) {
58
63
  const provided = ctx.payload?.password
59
- if (!provided || !ChatRoom.safeCompare(ChatRoom.hashPassword(provided), this.meta.password)) {
64
+ if (!provided || !ChatRoom.verifyPassword(provided, this.meta.password)) {
60
65
  return false // Rejected — wrong or missing password
61
66
  }
62
67
  }
@@ -3,6 +3,7 @@ import { usersRoutes } from "./users.routes"
3
3
  import { roomRoutes } from "./room.routes"
4
4
  import { authRoutes } from "./auth.routes"
5
5
  import { pluginClientHooks } from "@core/server/plugin-client-hooks"
6
+ import { FLUXSTACK_VERSION } from "@core/utils/version"
6
7
 
7
8
  export const apiRoutes = new Elysia({ prefix: "/api" })
8
9
  .get("/", () => ({ message: "🔥 Hot Reload funcionando! FluxStack API v1.4.0 ⚡" }), {
@@ -15,24 +16,33 @@ export const apiRoutes = new Elysia({ prefix: "/api" })
15
16
  description: 'Returns a welcome message from the FluxStack API'
16
17
  }
17
18
  })
18
- .get("/health", () => ({
19
- status: "🚀 Hot Reload ativo!",
20
- timestamp: new Date().toISOString(),
21
- uptime: `${Math.floor(process.uptime())}s`,
22
- version: "1.4.0",
23
- environment: "development"
24
- }), {
19
+ .get("/health", () => {
20
+ const checks = {
21
+ status: 'ok' as 'ok' | 'degraded' | 'error',
22
+ timestamp: new Date().toISOString(),
23
+ uptime: process.uptime(),
24
+ memory: {
25
+ used: Math.round(process.memoryUsage().heapUsed / 1024 / 1024),
26
+ total: Math.round(process.memoryUsage().heapTotal / 1024 / 1024),
27
+ },
28
+ version: FLUXSTACK_VERSION,
29
+ }
30
+ return checks
31
+ }, {
25
32
  response: t.Object({
26
33
  status: t.String(),
27
34
  timestamp: t.String(),
28
- uptime: t.String(),
35
+ uptime: t.Number(),
36
+ memory: t.Object({
37
+ used: t.Number(),
38
+ total: t.Number(),
39
+ }),
29
40
  version: t.String(),
30
- environment: t.String()
31
41
  }),
32
42
  detail: {
33
43
  tags: ['Health'],
34
44
  summary: 'Health Check',
35
- description: 'Returns the current health status of the API server'
45
+ description: 'Returns the current health status of the API including uptime, memory usage, and version'
36
46
  }
37
47
  })
38
48
  // Plugin client hooks endpoint
@@ -6,7 +6,7 @@ import { Bundler } from "./bundler"
6
6
  import { Optimizer } from "./optimizer"
7
7
  import { FLUXSTACK_VERSION } from "../utils/version"
8
8
  import { buildLogger } from "../utils/build-logger"
9
- import type { PluginRegistry } from "../plugins/registry"
9
+ import type { PluginRegistry } from "@fluxstack/plugin-kit"
10
10
  import type { BuildContext, BuildAssetContext, BuildErrorContext } from "../plugins/types"
11
11
 
12
12
  /**
@@ -4,7 +4,7 @@ import { logger } from "@core/utils/logger"
4
4
  import { buildLogger } from "@core/utils/build-logger"
5
5
  import { createTimer, formatBytes, isProduction, isDevelopment } from "../utils/helpers"
6
6
  import { createHash } from "crypto"
7
- import { createPluginUtils } from "../plugins/config"
7
+ import { createPluginUtils } from "@fluxstack/plugin-kit"
8
8
 
9
9
  export class CliCommandRegistry {
10
10
  private commands = new Map<string, CliCommand>()
@@ -6,6 +6,13 @@
6
6
  import type { CLICommand } from '../command-registry'
7
7
  import { FluxStackBuilder } from '@core/build'
8
8
  import { fluxStackConfig } from '@config'
9
+ import {
10
+ PluginRegistry,
11
+ PluginManager,
12
+ type FluxStack,
13
+ } from '@fluxstack/plugin-kit'
14
+ import type { FluxStackConfig } from '@config'
15
+ import { pluginClientHooks } from '@core/server/plugin-client-hooks'
9
16
 
10
17
  export const buildCommand: CLICommand = {
11
18
  name: 'build',
@@ -38,18 +45,30 @@ export const buildCommand: CLICommand = {
38
45
  handler: async (args, options, context) => {
39
46
  const config = fluxStackConfig
40
47
 
41
- // Load plugins for build hooks
42
- const { PluginRegistry } = await import('@core/plugins/registry')
43
- const { PluginManager } = await import('@core/plugins/manager')
44
- const pluginRegistry = new PluginRegistry({ config, logger: context.logger })
45
- const pluginManager = new PluginManager({ config, logger: context.logger })
48
+ // Load plugins for build hooks. PluginRegistry + PluginManager now
49
+ // come from @fluxstack/plugin-kit (the single source of truth).
50
+ // Both constructors expect the plugin-related config slice explicitly
51
+ // via `settings`, and the manager additionally requires `clientHooks`.
52
+ const pluginRegistry = new PluginRegistry({
53
+ logger: context.logger,
54
+ settings: config.plugins,
55
+ })
56
+ const pluginManager = new PluginManager<FluxStackConfig>({
57
+ config,
58
+ settings: config.plugins,
59
+ logger: context.logger,
60
+ clientHooks: {
61
+ register: (hookName: string, jsCode: string) =>
62
+ pluginClientHooks.register(hookName, jsCode),
63
+ },
64
+ })
46
65
 
47
66
  try {
48
67
  await pluginManager.initialize()
49
68
  // Sync plugins to registry (same as framework does)
50
69
  const discoveredPlugins = pluginManager.getRegistry().getAll()
51
70
  const registryInternals = pluginRegistry as unknown as {
52
- plugins: Map<string, import('@core/plugins/types').FluxStack.Plugin>
71
+ plugins: Map<string, FluxStack.Plugin>
53
72
  dependencies: Map<string, string[]>
54
73
  loadOrder: string[]
55
74
  updateLoadOrder(): void
@@ -4,8 +4,7 @@
4
4
 
5
5
  import { Command } from 'commander'
6
6
  import { buildLogger } from '@core/utils/build-logger'
7
- import { PluginDependencyManager } from '@core/plugins/dependency-manager'
8
- import { PluginRegistry } from '@core/plugins/registry'
7
+ import { PluginDependencyManager, PluginRegistry } from '@fluxstack/plugin-kit'
9
8
  import { existsSync, readFileSync } from 'fs'
10
9
  import { join } from 'path'
11
10