create-fluxstack 1.12.1 → 1.14.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 (116) hide show
  1. package/LLMD/INDEX.md +8 -1
  2. package/LLMD/agent.md +867 -0
  3. package/LLMD/config/environment-vars.md +30 -0
  4. package/LLMD/patterns/anti-patterns.md +100 -0
  5. package/LLMD/reference/routing.md +39 -39
  6. package/LLMD/resources/live-auth.md +465 -0
  7. package/LLMD/resources/live-components.md +168 -26
  8. package/LLMD/resources/live-logging.md +220 -0
  9. package/LLMD/resources/live-upload.md +59 -8
  10. package/LLMD/resources/rest-auth.md +290 -0
  11. package/README.md +520 -340
  12. package/app/client/index.html +2 -2
  13. package/app/client/public/favicon.svg +46 -0
  14. package/app/client/src/App.tsx +13 -1
  15. package/app/client/src/assets/fluxstack-static.svg +46 -0
  16. package/app/client/src/assets/fluxstack.svg +183 -0
  17. package/app/client/src/components/AppLayout.tsx +139 -9
  18. package/app/client/src/components/BackButton.tsx +13 -13
  19. package/app/client/src/components/DemoPage.tsx +4 -4
  20. package/app/client/src/live/AuthDemo.tsx +334 -0
  21. package/app/client/src/live/ChatDemo.tsx +2 -2
  22. package/app/client/src/live/CounterDemo.tsx +12 -12
  23. package/app/client/src/live/FormDemo.tsx +2 -2
  24. package/app/client/src/live/LiveDebuggerPanel.tsx +779 -0
  25. package/app/client/src/live/RoomChatDemo.tsx +24 -16
  26. package/app/client/src/main.tsx +13 -13
  27. package/app/client/src/pages/ApiTestPage.tsx +6 -6
  28. package/app/client/src/pages/HomePage.tsx +80 -52
  29. package/app/server/auth/AuthManager.ts +213 -0
  30. package/app/server/auth/DevAuthProvider.ts +66 -0
  31. package/app/server/auth/HashManager.ts +123 -0
  32. package/app/server/auth/JWTAuthProvider.example.ts +101 -0
  33. package/app/server/auth/RateLimiter.ts +106 -0
  34. package/app/server/auth/contracts.ts +192 -0
  35. package/app/server/auth/guards/SessionGuard.ts +167 -0
  36. package/app/server/auth/guards/TokenGuard.ts +202 -0
  37. package/app/server/auth/index.ts +174 -0
  38. package/app/server/auth/middleware.ts +163 -0
  39. package/app/server/auth/providers/InMemoryProvider.ts +162 -0
  40. package/app/server/auth/sessions/SessionManager.ts +164 -0
  41. package/app/server/cache/CacheManager.ts +81 -0
  42. package/app/server/cache/MemoryDriver.ts +112 -0
  43. package/app/server/cache/contracts.ts +49 -0
  44. package/app/server/cache/index.ts +42 -0
  45. package/app/server/index.ts +14 -0
  46. package/app/server/live/LiveAdminPanel.ts +174 -0
  47. package/app/server/live/LiveChat.ts +78 -77
  48. package/app/server/live/LiveCounter.ts +1 -0
  49. package/app/server/live/LiveForm.ts +1 -0
  50. package/app/server/live/LiveLocalCounter.ts +38 -32
  51. package/app/server/live/LiveProtectedChat.ts +151 -0
  52. package/app/server/live/LiveRoomChat.ts +1 -0
  53. package/app/server/live/LiveUpload.ts +1 -0
  54. package/app/server/live/register-components.ts +19 -19
  55. package/app/server/routes/auth.routes.ts +278 -0
  56. package/app/server/routes/index.ts +2 -0
  57. package/config/index.ts +8 -0
  58. package/config/system/auth.config.ts +49 -0
  59. package/config/system/runtime.config.ts +4 -0
  60. package/config/system/session.config.ts +33 -0
  61. package/core/build/optimizer.ts +235 -235
  62. package/core/client/LiveComponentsProvider.tsx +76 -5
  63. package/core/client/components/Live.tsx +17 -10
  64. package/core/client/components/LiveDebugger.tsx +1324 -0
  65. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -215
  66. package/core/client/hooks/useLiveComponent.ts +58 -5
  67. package/core/client/hooks/useLiveDebugger.ts +392 -0
  68. package/core/client/index.ts +16 -1
  69. package/core/framework/server.ts +36 -4
  70. package/core/plugins/built-in/index.ts +134 -134
  71. package/core/plugins/built-in/live-components/commands/create-live-component.ts +19 -8
  72. package/core/plugins/built-in/monitoring/index.ts +10 -3
  73. package/core/plugins/built-in/vite/index.ts +151 -20
  74. package/core/plugins/config.ts +5 -4
  75. package/core/plugins/discovery.ts +11 -2
  76. package/core/plugins/manager.ts +11 -5
  77. package/core/plugins/module-resolver.ts +1 -1
  78. package/core/plugins/registry.ts +53 -25
  79. package/core/server/index.ts +15 -15
  80. package/core/server/live/ComponentRegistry.ts +134 -50
  81. package/core/server/live/FileUploadManager.ts +188 -24
  82. package/core/server/live/LiveComponentPerformanceMonitor.ts +9 -8
  83. package/core/server/live/LiveDebugger.ts +462 -0
  84. package/core/server/live/LiveLogger.ts +144 -0
  85. package/core/server/live/LiveRoomManager.ts +22 -5
  86. package/core/server/live/StateSignature.ts +704 -643
  87. package/core/server/live/WebSocketConnectionManager.ts +11 -10
  88. package/core/server/live/auth/LiveAuthContext.ts +71 -0
  89. package/core/server/live/auth/LiveAuthManager.ts +304 -0
  90. package/core/server/live/auth/index.ts +19 -0
  91. package/core/server/live/auth/types.ts +179 -0
  92. package/core/server/live/auto-generated-components.ts +8 -2
  93. package/core/server/live/index.ts +16 -0
  94. package/core/server/live/websocket-plugin.ts +323 -22
  95. package/core/server/plugins/static-files-plugin.ts +179 -69
  96. package/core/templates/create-project.ts +0 -3
  97. package/core/types/build.ts +219 -219
  98. package/core/types/plugin.ts +107 -107
  99. package/core/types/types.ts +278 -22
  100. package/core/utils/index.ts +17 -17
  101. package/core/utils/logger/index.ts +5 -2
  102. package/core/utils/logger/startup-banner.ts +82 -82
  103. package/core/utils/version.ts +6 -6
  104. package/package.json +1 -8
  105. package/plugins/crypto-auth/index.ts +6 -0
  106. package/plugins/crypto-auth/server/CryptoAuthLiveProvider.ts +58 -0
  107. package/plugins/crypto-auth/server/index.ts +24 -21
  108. package/rest-tests/README.md +57 -0
  109. package/rest-tests/auth-token.http +113 -0
  110. package/rest-tests/auth.http +112 -0
  111. package/rest-tests/rooms-token.http +69 -0
  112. package/rest-tests/users-token.http +62 -0
  113. package/.dockerignore +0 -81
  114. package/Dockerfile +0 -70
  115. package/LIVE_COMPONENTS_REVIEW.md +0 -781
  116. package/app/client/src/assets/react.svg +0 -1
@@ -47,11 +47,11 @@ export function RoomChatDemo() {
47
47
  }
48
48
 
49
49
  return (
50
- <div className="flex h-[600px] bg-gray-900 rounded-2xl overflow-hidden border border-white/10">
50
+ <div className="flex flex-col md:flex-row h-[calc(100vh-200px)] md:h-[600px] w-full max-w-4xl mx-auto bg-gray-900 rounded-2xl overflow-hidden border border-white/10">
51
51
  {/* Sidebar */}
52
- <div className="w-64 bg-gray-800/50 border-r border-white/10 flex flex-col">
52
+ <div className={`${activeRoom ? 'hidden md:flex' : 'flex'} w-full md:w-64 bg-gray-800/50 md:border-r border-white/10 flex-col ${!activeRoom ? 'flex-1 md:flex-initial' : ''}`}>
53
53
  <div className="p-4 border-b border-white/10">
54
- <h2 className="text-lg font-bold text-white mb-2">💬 Room Chat</h2>
54
+ <h2 className="text-lg font-bold text-white mb-2">Room Chat</h2>
55
55
  <div className="flex items-center gap-2">
56
56
  <div className={`w-2 h-2 rounded-full ${chat.$connected ? 'bg-emerald-400' : 'bg-red-400'}`} />
57
57
  <span className="text-sm text-gray-400">{chat.$state.username}</span>
@@ -94,15 +94,23 @@ export function RoomChatDemo() {
94
94
  </div>
95
95
 
96
96
  {/* Chat Area */}
97
- <div className="flex-1 flex flex-col">
97
+ <div className={`${!activeRoom ? 'hidden md:flex' : 'flex'} flex-1 flex-col`}>
98
98
  {activeRoom ? (
99
99
  <>
100
100
  <div className="px-4 py-3 border-b border-white/10 flex items-center justify-between">
101
- <div>
102
- <h3 className="text-white font-semibold">
103
- {chat.$state.rooms.find(r => r.id === activeRoom)?.name || activeRoom}
104
- </h3>
105
- <p className="text-xs text-gray-500">{activeMessages.length} mensagens</p>
101
+ <div className="flex items-center gap-3">
102
+ <button
103
+ onClick={() => chat.switchRoom({ roomId: '' })}
104
+ className="md:hidden px-2 py-1 text-sm text-gray-400 hover:text-white"
105
+ >
106
+
107
+ </button>
108
+ <div>
109
+ <h3 className="text-white font-semibold">
110
+ {chat.$state.rooms.find(r => r.id === activeRoom)?.name || activeRoom}
111
+ </h3>
112
+ <p className="text-xs text-gray-500">{activeMessages.length} mensagens</p>
113
+ </div>
106
114
  </div>
107
115
  <button
108
116
  onClick={() => chat.leaveRoom({ roomId: activeRoom })}
@@ -110,7 +118,7 @@ export function RoomChatDemo() {
110
118
  >Sair</button>
111
119
  </div>
112
120
 
113
- <div className="flex-1 overflow-auto p-4 space-y-3">
121
+ <div className="flex-1 overflow-auto p-3 sm:p-4 space-y-3">
114
122
  {activeMessages.length === 0 ? (
115
123
  <div className="text-center text-gray-500 py-8">
116
124
  <p>Nenhuma mensagem ainda</p>
@@ -119,9 +127,9 @@ export function RoomChatDemo() {
119
127
  ) : (
120
128
  activeMessages.map(msg => (
121
129
  <div key={msg.id} className={`flex flex-col ${msg.user === chat.$state.username ? 'items-end' : 'items-start'}`}>
122
- <div className={`max-w-[80%] rounded-2xl px-4 py-2 ${msg.user === chat.$state.username ? 'bg-purple-500/30 text-purple-100' : 'bg-white/10 text-gray-200'}`}>
130
+ <div className={`max-w-[85%] sm:max-w-[80%] rounded-2xl px-3 sm:px-4 py-2 ${msg.user === chat.$state.username ? 'bg-purple-500/30 text-purple-100' : 'bg-white/10 text-gray-200'}`}>
123
131
  <p className="text-xs text-gray-400 mb-1">{msg.user}</p>
124
- <p>{msg.text}</p>
132
+ <p className="text-sm sm:text-base">{msg.text}</p>
125
133
  </div>
126
134
  <span className="text-xs text-gray-600 mt-1">{new Date(msg.timestamp).toLocaleTimeString()}</span>
127
135
  </div>
@@ -130,19 +138,19 @@ export function RoomChatDemo() {
130
138
  <div ref={messagesEndRef} />
131
139
  </div>
132
140
 
133
- <div className="p-4 border-t border-white/10">
141
+ <div className="p-3 sm:p-4 border-t border-white/10">
134
142
  <div className="flex gap-2">
135
143
  <input
136
144
  value={text}
137
145
  onChange={(e) => setText(e.target.value)}
138
146
  onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSendMessage() } }}
139
147
  placeholder="Digite uma mensagem..."
140
- className="flex-1 px-4 py-2 rounded-xl bg-white/10 border border-white/20 text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500/50"
148
+ className="flex-1 px-3 sm:px-4 py-2 rounded-xl bg-white/10 border border-white/20 text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500/50 text-sm sm:text-base"
141
149
  />
142
150
  <button
143
151
  onClick={handleSendMessage}
144
152
  disabled={!text.trim()}
145
- className="px-6 py-2 rounded-xl bg-purple-500/30 text-purple-200 hover:bg-purple-500/40 disabled:opacity-50"
153
+ className="px-4 sm:px-6 py-2 rounded-xl bg-purple-500/30 text-purple-200 hover:bg-purple-500/40 disabled:opacity-50 text-sm sm:text-base"
146
154
  >Enviar</button>
147
155
  </div>
148
156
  </div>
@@ -150,7 +158,7 @@ export function RoomChatDemo() {
150
158
  ) : (
151
159
  <div className="flex-1 flex items-center justify-center text-gray-500">
152
160
  <div className="text-center">
153
- <p className="text-4xl mb-4">👈</p>
161
+ <p className="text-4xl mb-4">←</p>
154
162
  <p>Selecione uma sala para começar</p>
155
163
  </div>
156
164
  </div>
@@ -1,13 +1,13 @@
1
- import { StrictMode } from 'react'
2
- import { createRoot } from 'react-dom/client'
3
- import { BrowserRouter } from 'react-router'
4
- import './index.css'
5
- import App from './App.tsx'
6
-
7
- createRoot(document.getElementById('root')!).render(
8
- <StrictMode>
9
- <BrowserRouter>
10
- <App />
11
- </BrowserRouter>
12
- </StrictMode>,
13
- )
1
+ import { StrictMode } from 'react'
2
+ import { createRoot } from 'react-dom/client'
3
+ import { BrowserRouter } from 'react-router'
4
+ import './index.css'
5
+ import App from './App.tsx'
6
+
7
+ createRoot(document.getElementById('root')!).render(
8
+ <StrictMode>
9
+ <BrowserRouter>
10
+ <App />
11
+ </BrowserRouter>
12
+ </StrictMode>,
13
+ )
@@ -15,10 +15,10 @@ export function ApiTestPage({
15
15
  onCreateUser: () => void
16
16
  }) {
17
17
  return (
18
- <div className="container mx-auto px-4 py-8 max-w-4xl">
19
- <div className="flex items-center gap-4 mb-8">
18
+ <div className="container mx-auto px-3 sm:px-4 py-6 sm:py-8 max-w-4xl">
19
+ <div className="flex items-center gap-3 sm:gap-4 mb-6 sm:mb-8">
20
20
  <BackButton />
21
- <h1 className="text-3xl font-bold bg-gradient-to-r from-blue-400 via-purple-400 to-pink-400 bg-clip-text text-transparent">
21
+ <h1 className="text-2xl sm:text-3xl font-bold bg-gradient-to-r from-blue-400 via-purple-400 to-pink-400 bg-clip-text text-transparent">
22
22
  Eden Treaty API Test
23
23
  </h1>
24
24
  </div>
@@ -50,7 +50,7 @@ export function ApiTestPage({
50
50
  />
51
51
  </div>
52
52
 
53
- <div className="bg-black/40 backdrop-blur-sm border border-white/10 rounded-2xl p-6">
53
+ <div className="bg-black/40 backdrop-blur-sm border border-white/10 rounded-2xl p-4 sm:p-6">
54
54
  <div className="flex items-center justify-between mb-4">
55
55
  <h2 className="text-lg font-semibold text-white">Response</h2>
56
56
  {isLoading && (
@@ -67,7 +67,7 @@ export function ApiTestPage({
67
67
  </pre>
68
68
  </div>
69
69
 
70
- <div className="mt-8 bg-white/5 border border-white/10 rounded-xl p-6">
70
+ <div className="mt-6 sm:mt-8 bg-white/5 border border-white/10 rounded-xl p-4 sm:p-6">
71
71
  <h3 className="text-lg font-semibold text-white mb-3">How it works</h3>
72
72
  <div className="text-gray-400 text-sm space-y-2">
73
73
  <p>OK <code className="text-purple-400">api.health.get()</code> - Full type inference from server</p>
@@ -98,7 +98,7 @@ function ActionCard({
98
98
  <button
99
99
  onClick={onClick}
100
100
  disabled={disabled}
101
- className={`px-6 py-4 border rounded-xl font-medium transition-all disabled:opacity-50 ${className}`}
101
+ className={`px-4 sm:px-6 py-3 sm:py-4 border rounded-xl font-medium transition-all disabled:opacity-50 text-sm sm:text-base ${className}`}
102
102
  >
103
103
  <div className="text-2xl mb-2">{icon}</div>
104
104
  <div>{title}</div>
@@ -1,76 +1,104 @@
1
- import { Link } from 'react-router'
2
- import { FaFire } from 'react-icons/fa'
1
+ import FluxStack from '@client/src/assets/fluxstack.svg'
3
2
 
4
3
  export function HomePage({ apiStatus }: { apiStatus: 'checking' | 'online' | 'offline' }) {
5
4
  return (
6
- <div className="flex flex-col items-center justify-center min-h-[calc(100vh-72px)] px-6 text-center">
7
- <div className="mb-8 animate-pulse-slow">
8
- <FaFire className="text-8xl text-orange-500 drop-shadow-2xl" />
9
- </div>
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">
10
6
 
11
- <h1 className="text-6xl md:text-7xl font-bold mb-4 bg-gradient-to-r from-blue-400 via-purple-400 to-pink-400 bg-clip-text text-transparent">
12
- FluxStack
13
- </h1>
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" />
14
9
 
15
- <p className="text-xl md:text-2xl text-gray-300 mb-8 max-w-2xl">
16
- Full-stack TypeScript framework with{' '}
17
- <span className="text-purple-400 font-semibold">Bun</span>,{' '}
18
- <span className="text-blue-400 font-semibold">Elysia</span>, and{' '}
19
- <span className="text-cyan-400 font-semibold">React</span>
20
- </p>
10
+ <div className="relative z-10 flex flex-col items-center w-full max-w-3xl">
21
11
 
22
- <div className="mb-12">
23
- <div className={`inline-flex items-center gap-2 px-4 py-2 rounded-full text-sm font-medium transition-all ${
24
- apiStatus === 'online'
25
- ? 'bg-emerald-500/20 text-emerald-300 border border-emerald-500/30'
26
- : apiStatus === 'offline'
27
- ? 'bg-red-500/20 text-red-300 border border-red-500/30'
28
- : 'bg-yellow-500/20 text-yellow-300 border border-yellow-500/30'
29
- }`}>
30
- <div className={`w-2 h-2 rounded-full ${
31
- apiStatus === 'online' ? 'bg-emerald-400' : apiStatus === 'offline' ? 'bg-red-400' : 'bg-yellow-400'
32
- }`}></div>
33
- <span>{apiStatus === 'checking' ? 'Checking API...' : apiStatus === 'online' ? 'API Online' : 'API Offline'}</span>
12
+ {/* Icon */}
13
+ <div className="relative mb-5">
14
+ <div className="absolute inset-0 bg-purple-500/20 rounded-full blur-2xl animate-pulse-slow" />
15
+ <img
16
+ src={FluxStack}
17
+ alt="FluxStack"
18
+ className="relative w-16 h-16 sm:w-20 sm:h-20 md:w-24 md:h-24 drop-shadow-[0_0_24px_rgba(168,85,247,0.35)] animate-float"
19
+ />
34
20
  </div>
35
- </div>
36
21
 
37
- <div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-12 max-w-4xl">
38
- <div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-6 hover:bg-white/10 transition-all">
39
- <div className="text-3xl mb-3">⚡</div>
40
- <h3 className="text-lg font-semibold text-white mb-2">Ultra Rápido</h3>
41
- <p className="text-gray-400 text-sm">Bun runtime 3x mais rápido que Node.js</p>
42
- </div>
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">
24
+ FluxStack
25
+ </h1>
43
26
 
44
- <div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-6 hover:bg-white/10 transition-all">
45
- <div className="text-3xl mb-3">🔒</div>
46
- <h3 className="text-lg font-semibold text-white mb-2">Type Safe</h3>
47
- <p className="text-gray-400 text-sm">Eden Treaty com inferência automática</p>
48
- </div>
27
+ {/* Subtitle */}
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>
30
+ {' + '}
31
+ <span className="text-indigo-400 font-semibold">Elysia</span>
32
+ {' + '}
33
+ <span className="text-cyan-400 font-semibold">React</span>
34
+ {' = '}
35
+ <span className="text-white font-semibold">FluxStack</span>
36
+ </p>
49
37
 
50
- <div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-6 hover:bg-white/10 transition-all">
51
- <div className="text-3xl mb-3">🔥</div>
52
- <h3 className="text-lg font-semibold text-white mb-2">Live Components</h3>
53
- <p className="text-gray-400 text-sm">Estado reativo no servidor estilo Livewire</p>
38
+ {/* API Status */}
39
+ <div className="mb-10 md:mb-12">
40
+ <div className={`inline-flex items-center gap-2 px-3 py-1.5 rounded-full text-[10px] sm:text-xs font-medium tracking-wide uppercase transition-all ${
41
+ apiStatus === 'online'
42
+ ? 'bg-emerald-500/10 text-emerald-400 border border-emerald-500/20'
43
+ : apiStatus === 'offline'
44
+ ? 'bg-red-500/10 text-red-400 border border-red-500/20'
45
+ : 'bg-yellow-500/10 text-yellow-400 border border-yellow-500/20'
46
+ }`}>
47
+ <div className={`w-1.5 h-1.5 rounded-full animate-pulse ${
48
+ apiStatus === 'online' ? 'bg-emerald-400' : apiStatus === 'offline' ? 'bg-red-400' : 'bg-yellow-400'
49
+ }`} />
50
+ <span>{apiStatus === 'checking' ? 'Checking API...' : apiStatus === 'online' ? 'API Online' : 'API Offline'}</span>
51
+ </div>
54
52
  </div>
55
- </div>
56
53
 
57
- <div className="mt-4 text-gray-500 text-sm">
58
- Use a navegação no topo para acessar as demos.
59
- </div>
54
+ {/* Feature cards */}
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">
58
+ <span className="text-sm">⚡</span>
59
+ </div>
60
+ <h3 className="text-xs sm:text-sm font-semibold text-white mb-1 text-left">Ultra Rápido</h3>
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
+ </div>
60
63
 
61
- <div className="mt-16 text-gray-500 text-sm">
62
- <p>Desenvolvido com ❤️ usando TypeScript</p>
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">
66
+ <span className="text-sm">🔒</span>
67
+ </div>
68
+ <h3 className="text-xs sm:text-sm font-semibold text-white mb-1 text-left">Type Safe</h3>
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
+ </div>
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">
74
+ <span className="text-sm">🔥</span>
75
+ </div>
76
+ <h3 className="text-xs sm:text-sm font-semibold text-white mb-1 text-left">Live Components</h3>
77
+ <p className="text-gray-500 text-[11px] sm:text-xs text-left leading-relaxed">Estado reativo no servidor inspirado no Livewire</p>
78
+ </div>
79
+ </div>
80
+
81
+ <p className="text-gray-600 text-[11px] tracking-wide">
82
+ Desenvolvido com ❤️ usando TypeScript
83
+ </p>
63
84
  </div>
64
85
 
65
86
  <style>{`
66
87
  @keyframes pulse-slow {
67
88
  0%, 100% { opacity: 1; }
68
- 50% { opacity: 0.8; }
89
+ 50% { opacity: 0.5; }
90
+ }
91
+ @keyframes float {
92
+ 0%, 100% { transform: translateY(0); }
93
+ 50% { transform: translateY(-6px); }
69
94
  }
70
95
  .animate-pulse-slow {
71
- animation: pulse-slow 3s cubic-bezier(0.4, 0, 0.6, 1) infinite;
96
+ animation: pulse-slow 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
97
+ }
98
+ .animate-float {
99
+ animation: float 5s ease-in-out infinite;
72
100
  }
73
101
  `}</style>
74
102
  </div>
75
103
  )
76
- }
104
+ }
@@ -0,0 +1,213 @@
1
+ /**
2
+ * FluxStack Auth - Auth Manager
3
+ *
4
+ * Orquestrador central do sistema de autenticação.
5
+ * Factory pattern com lazy resolution e cache de guards.
6
+ *
7
+ * Inspirado no AuthManager do Laravel:
8
+ * - Resolve guards por nome (ou default)
9
+ * - Extensível com extend() para guards customizados
10
+ * - Resolve providers automaticamente da config
11
+ *
12
+ * ```ts
13
+ * // Usar guard padrão
14
+ * const user = await auth.guard().user()
15
+ *
16
+ * // Usar guard específico
17
+ * const apiUser = await auth.guard('api').user()
18
+ *
19
+ * // Registrar guard customizado
20
+ * auth.extend('jwt', (name, config, provider) => new JWTGuard(...))
21
+ * ```
22
+ */
23
+
24
+ import type {
25
+ Guard,
26
+ UserProvider,
27
+ GuardConfig,
28
+ GuardFactory,
29
+ RequestContext,
30
+ } from './contracts'
31
+ import { SessionGuard } from './guards/SessionGuard'
32
+ import { TokenGuard } from './guards/TokenGuard'
33
+ import { SessionManager } from './sessions/SessionManager'
34
+ import { cacheManager } from '@server/cache'
35
+
36
+ export interface AuthManagerConfig {
37
+ defaults: {
38
+ guard: string
39
+ provider: string
40
+ }
41
+ guards: Record<string, GuardConfig>
42
+ providers: Record<string, ProviderConfig>
43
+ }
44
+
45
+ export interface ProviderConfig {
46
+ driver: string
47
+ [key: string]: unknown
48
+ }
49
+
50
+ export class AuthManager {
51
+ private config: AuthManagerConfig
52
+ private guards = new Map<string, Guard>()
53
+ private customGuardFactories = new Map<string, GuardFactory>()
54
+ private providerInstances = new Map<string, UserProvider>()
55
+ private customProviderFactories = new Map<string, (config: ProviderConfig) => UserProvider>()
56
+ private sessionManager: SessionManager
57
+
58
+ constructor(config: AuthManagerConfig, sessionManager: SessionManager) {
59
+ this.config = config
60
+ this.sessionManager = sessionManager
61
+ }
62
+
63
+ /**
64
+ * Retorna um guard por nome (ou o default).
65
+ * Guards são criados uma vez e reutilizados.
66
+ */
67
+ guard(name?: string): Guard {
68
+ const guardName = name ?? this.config.defaults.guard
69
+
70
+ if (this.guards.has(guardName)) {
71
+ return this.guards.get(guardName)!
72
+ }
73
+
74
+ const guard = this.resolve(guardName)
75
+ this.guards.set(guardName, guard)
76
+ return guard
77
+ }
78
+
79
+ /**
80
+ * Inicializa todos os guards com o contexto da request.
81
+ * Deve ser chamado no middleware, antes de qualquer uso.
82
+ */
83
+ setRequest(context: RequestContext): void {
84
+ for (const guard of this.guards.values()) {
85
+ guard.setRequest(context)
86
+ }
87
+ // Também resetar guards não-instanciados para forçar re-resolve com novo context
88
+ }
89
+
90
+ /**
91
+ * Cria um guard novo (sem cache) com o context da request.
92
+ * Útil quando precisa de um guard fresco para cada request.
93
+ */
94
+ freshGuard(name?: string, context?: RequestContext): Guard {
95
+ const guardName = name ?? this.config.defaults.guard
96
+ const guard = this.resolve(guardName)
97
+ if (context) {
98
+ guard.setRequest(context)
99
+ }
100
+ return guard
101
+ }
102
+
103
+ /**
104
+ * Registra um guard driver customizado.
105
+ *
106
+ * ```ts
107
+ * auth.extend('jwt', (name, config, provider) => {
108
+ * return new JWTGuard(name, provider, config.secret)
109
+ * })
110
+ * ```
111
+ */
112
+ extend(driver: string, factory: GuardFactory): void {
113
+ this.customGuardFactories.set(driver, factory)
114
+ }
115
+
116
+ /**
117
+ * Registra um provider customizado.
118
+ *
119
+ * ```ts
120
+ * auth.extendProvider('drizzle', (config) => {
121
+ * return new DrizzleUserProvider(db, config.table)
122
+ * })
123
+ * ```
124
+ */
125
+ extendProvider(driver: string, factory: (config: ProviderConfig) => UserProvider): void {
126
+ this.customProviderFactories.set(driver, factory)
127
+ }
128
+
129
+ /**
130
+ * Registra uma instância de provider diretamente.
131
+ */
132
+ registerProvider(name: string, provider: UserProvider): void {
133
+ this.providerInstances.set(name, provider)
134
+ }
135
+
136
+ /** Retorna o nome do guard padrão */
137
+ getDefaultGuardName(): string {
138
+ return this.config.defaults.guard
139
+ }
140
+
141
+ /** Retorna a config */
142
+ getConfig(): AuthManagerConfig {
143
+ return this.config
144
+ }
145
+
146
+ /** Resolve um guard por nome */
147
+ private resolve(name: string): Guard {
148
+ const guardConfig = this.config.guards[name]
149
+ if (!guardConfig) {
150
+ throw new Error(
151
+ `Auth guard '${name}' not configured. ` +
152
+ `Available: ${Object.keys(this.config.guards).join(', ')}`
153
+ )
154
+ }
155
+
156
+ // Resolver provider
157
+ const provider = this.resolveProvider(guardConfig.provider)
158
+
159
+ // Verificar custom factory primeiro
160
+ if (this.customGuardFactories.has(guardConfig.driver)) {
161
+ return this.customGuardFactories.get(guardConfig.driver)!(name, guardConfig, provider)
162
+ }
163
+
164
+ // Built-in drivers
165
+ switch (guardConfig.driver) {
166
+ case 'session':
167
+ return new SessionGuard(name, provider, this.sessionManager)
168
+
169
+ case 'token':
170
+ return new TokenGuard(
171
+ name,
172
+ provider,
173
+ cacheManager.driver(),
174
+ guardConfig.tokenTtl as number | undefined
175
+ )
176
+
177
+ default:
178
+ throw new Error(
179
+ `Auth guard driver '${guardConfig.driver}' not supported. ` +
180
+ `Use auth.extend('${guardConfig.driver}', factory) to register it.`
181
+ )
182
+ }
183
+ }
184
+
185
+ /** Resolve um provider por nome */
186
+ private resolveProvider(name: string): UserProvider {
187
+ // Cache de instâncias
188
+ if (this.providerInstances.has(name)) {
189
+ return this.providerInstances.get(name)!
190
+ }
191
+
192
+ const providerConfig = this.config.providers[name]
193
+ if (!providerConfig) {
194
+ throw new Error(
195
+ `Auth provider '${name}' not configured. ` +
196
+ `Available: ${Object.keys(this.config.providers).join(', ')}`
197
+ )
198
+ }
199
+
200
+ // Custom factory
201
+ if (this.customProviderFactories.has(providerConfig.driver)) {
202
+ const provider = this.customProviderFactories.get(providerConfig.driver)!(providerConfig)
203
+ this.providerInstances.set(name, provider)
204
+ return provider
205
+ }
206
+
207
+ throw new Error(
208
+ `Auth provider driver '${providerConfig.driver}' not supported. ` +
209
+ `Use auth.extendProvider('${providerConfig.driver}', factory) to register it, ` +
210
+ `or use auth.registerProvider('${name}', providerInstance) to register directly.`
211
+ )
212
+ }
213
+ }
@@ -0,0 +1,66 @@
1
+ // 🧪 DevAuthProvider - Provider de desenvolvimento para testes de auth
2
+ //
3
+ // Aceita tokens simples para facilitar testes da demo de autenticação.
4
+ // NÃO USAR EM PRODUÇÃO!
5
+ //
6
+ // Tokens válidos:
7
+ // - "admin-token" → role: admin, permissions: all
8
+ // - "user-token" → role: user, permissions: básicas
9
+ // - "mod-token" → role: moderator, permissions: moderação
10
+
11
+ import type {
12
+ LiveAuthProvider,
13
+ LiveAuthCredentials,
14
+ LiveAuthContext,
15
+ } from '@core/server/live/auth/types'
16
+ import { AuthenticatedContext } from '@core/server/live/auth/LiveAuthContext'
17
+
18
+ interface DevUser {
19
+ id: string
20
+ name: string
21
+ roles: string[]
22
+ permissions: string[]
23
+ }
24
+
25
+ const DEV_USERS: Record<string, DevUser> = {
26
+ 'admin-token': {
27
+ id: 'admin-1',
28
+ name: 'Admin User',
29
+ roles: ['admin', 'user'],
30
+ permissions: ['users.read', 'users.write', 'users.delete', 'chat.read', 'chat.write', 'chat.admin'],
31
+ },
32
+ 'user-token': {
33
+ id: 'user-1',
34
+ name: 'Regular User',
35
+ roles: ['user'],
36
+ permissions: ['chat.read', 'chat.write'],
37
+ },
38
+ 'mod-token': {
39
+ id: 'mod-1',
40
+ name: 'Moderator',
41
+ roles: ['moderator', 'user'],
42
+ permissions: ['chat.read', 'chat.write', 'chat.moderate'],
43
+ },
44
+ }
45
+
46
+ export class DevAuthProvider implements LiveAuthProvider {
47
+ readonly name = 'dev'
48
+
49
+ async authenticate(credentials: LiveAuthCredentials): Promise<LiveAuthContext | null> {
50
+ const token = credentials.token as string
51
+ if (!token) return null
52
+
53
+ const user = DEV_USERS[token]
54
+ if (!user) return null
55
+
56
+ return new AuthenticatedContext(
57
+ {
58
+ id: user.id,
59
+ name: user.name,
60
+ roles: user.roles,
61
+ permissions: user.permissions,
62
+ },
63
+ token
64
+ )
65
+ }
66
+ }