create-fluxstack 1.10.1 → 1.12.1

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 (257) hide show
  1. package/.dockerignore +1 -2
  2. package/Dockerfile +8 -8
  3. package/LLMD/INDEX.md +64 -0
  4. package/LLMD/MAINTENANCE.md +197 -0
  5. package/LLMD/MIGRATION.md +156 -0
  6. package/LLMD/config/.gitkeep +1 -0
  7. package/LLMD/config/declarative-system.md +268 -0
  8. package/LLMD/config/environment-vars.md +327 -0
  9. package/LLMD/config/runtime-reload.md +401 -0
  10. package/LLMD/core/.gitkeep +1 -0
  11. package/LLMD/core/build-system.md +599 -0
  12. package/LLMD/core/framework-lifecycle.md +229 -0
  13. package/LLMD/core/plugin-system.md +451 -0
  14. package/LLMD/patterns/.gitkeep +1 -0
  15. package/LLMD/patterns/anti-patterns.md +297 -0
  16. package/LLMD/patterns/project-structure.md +264 -0
  17. package/LLMD/patterns/type-safety.md +440 -0
  18. package/LLMD/reference/.gitkeep +1 -0
  19. package/LLMD/reference/cli-commands.md +250 -0
  20. package/LLMD/reference/plugin-hooks.md +357 -0
  21. package/LLMD/reference/routing.md +39 -0
  22. package/LLMD/reference/troubleshooting.md +364 -0
  23. package/LLMD/resources/.gitkeep +1 -0
  24. package/LLMD/resources/controllers.md +465 -0
  25. package/LLMD/resources/live-components.md +703 -0
  26. package/LLMD/resources/live-rooms.md +482 -0
  27. package/LLMD/resources/live-upload.md +130 -0
  28. package/LLMD/resources/plugins-external.md +617 -0
  29. package/LLMD/resources/routes-eden.md +254 -0
  30. package/README.md +37 -17
  31. package/app/client/index.html +0 -1
  32. package/app/client/src/App.tsx +107 -150
  33. package/app/client/src/components/AppLayout.tsx +68 -0
  34. package/app/client/src/components/BackButton.tsx +13 -0
  35. package/app/client/src/components/DemoPage.tsx +20 -0
  36. package/app/client/src/components/LiveUploadWidget.tsx +204 -0
  37. package/app/client/src/lib/eden-api.ts +85 -60
  38. package/app/client/src/live/ChatDemo.tsx +107 -0
  39. package/app/client/src/live/CounterDemo.tsx +206 -0
  40. package/app/client/src/live/FormDemo.tsx +119 -0
  41. package/app/client/src/live/RoomChatDemo.tsx +161 -0
  42. package/app/client/src/live/UploadDemo.tsx +21 -0
  43. package/app/client/src/main.tsx +4 -1
  44. package/app/client/src/pages/ApiTestPage.tsx +108 -0
  45. package/app/client/src/pages/HomePage.tsx +76 -0
  46. package/app/server/app.ts +1 -4
  47. package/app/server/controllers/users.controller.ts +36 -44
  48. package/app/server/index.ts +25 -35
  49. package/app/server/live/LiveChat.ts +77 -0
  50. package/app/server/live/LiveCounter.ts +67 -0
  51. package/app/server/live/LiveForm.ts +63 -0
  52. package/app/server/live/LiveLocalCounter.ts +32 -0
  53. package/app/server/live/LiveRoomChat.ts +127 -0
  54. package/app/server/live/LiveUpload.ts +81 -0
  55. package/app/server/routes/index.ts +3 -1
  56. package/app/server/routes/room.routes.ts +117 -0
  57. package/app/server/routes/users.routes.ts +35 -27
  58. package/app/shared/types/index.ts +14 -2
  59. package/config/app.config.ts +2 -62
  60. package/config/client.config.ts +2 -95
  61. package/config/database.config.ts +2 -99
  62. package/config/fluxstack.config.ts +25 -45
  63. package/config/index.ts +57 -38
  64. package/config/monitoring.config.ts +2 -114
  65. package/config/plugins.config.ts +2 -80
  66. package/config/server.config.ts +2 -68
  67. package/config/services.config.ts +2 -130
  68. package/config/system/app.config.ts +29 -0
  69. package/config/system/build.config.ts +49 -0
  70. package/config/system/client.config.ts +68 -0
  71. package/config/system/database.config.ts +17 -0
  72. package/config/system/fluxstack.config.ts +114 -0
  73. package/config/{logger.config.ts → system/logger.config.ts} +3 -1
  74. package/config/system/monitoring.config.ts +114 -0
  75. package/config/system/plugins.config.ts +84 -0
  76. package/config/{runtime.config.ts → system/runtime.config.ts} +1 -1
  77. package/config/system/server.config.ts +68 -0
  78. package/config/system/services.config.ts +46 -0
  79. package/config/{system.config.ts → system/system.config.ts} +1 -1
  80. package/core/build/flux-plugins-generator.ts +325 -325
  81. package/core/build/index.ts +39 -27
  82. package/core/build/live-components-generator.ts +3 -3
  83. package/core/build/optimizer.ts +235 -235
  84. package/core/cli/command-registry.ts +6 -4
  85. package/core/cli/commands/build.ts +79 -0
  86. package/core/cli/commands/create.ts +54 -0
  87. package/core/cli/commands/dev.ts +101 -0
  88. package/core/cli/commands/help.ts +34 -0
  89. package/core/cli/commands/index.ts +34 -0
  90. package/core/cli/commands/make-plugin.ts +90 -0
  91. package/core/cli/commands/plugin-add.ts +197 -0
  92. package/core/cli/commands/plugin-deps.ts +2 -2
  93. package/core/cli/commands/plugin-list.ts +208 -0
  94. package/core/cli/commands/plugin-remove.ts +170 -0
  95. package/core/cli/generators/component.ts +769 -769
  96. package/core/cli/generators/controller.ts +1 -1
  97. package/core/cli/generators/index.ts +146 -146
  98. package/core/cli/generators/interactive.ts +227 -227
  99. package/core/cli/generators/plugin.ts +2 -2
  100. package/core/cli/generators/prompts.ts +82 -82
  101. package/core/cli/generators/route.ts +6 -6
  102. package/core/cli/generators/service.ts +2 -2
  103. package/core/cli/generators/template-engine.ts +4 -3
  104. package/core/cli/generators/types.ts +2 -2
  105. package/core/cli/generators/utils.ts +191 -191
  106. package/core/cli/index.ts +115 -686
  107. package/core/cli/plugin-discovery.ts +2 -2
  108. package/core/client/LiveComponentsProvider.tsx +60 -8
  109. package/core/client/api/eden.ts +183 -0
  110. package/core/client/api/index.ts +11 -0
  111. package/core/client/components/Live.tsx +104 -0
  112. package/core/client/fluxstack.ts +1 -9
  113. package/core/client/hooks/AdaptiveChunkSizer.ts +215 -215
  114. package/core/client/hooks/state-validator.ts +1 -1
  115. package/core/client/hooks/useAuth.ts +48 -48
  116. package/core/client/hooks/useChunkedUpload.ts +85 -35
  117. package/core/client/hooks/useLiveChunkedUpload.ts +87 -0
  118. package/core/client/hooks/useLiveComponent.ts +800 -0
  119. package/core/client/hooks/useLiveUpload.ts +71 -0
  120. package/core/client/hooks/useRoom.ts +409 -0
  121. package/core/client/hooks/useRoomProxy.ts +382 -0
  122. package/core/client/index.ts +17 -68
  123. package/core/client/standalone-entry.ts +8 -0
  124. package/core/client/standalone.ts +74 -53
  125. package/core/client/state/createStore.ts +192 -192
  126. package/core/client/state/index.ts +14 -14
  127. package/core/config/index.ts +70 -291
  128. package/core/config/schema.ts +42 -723
  129. package/core/framework/client.ts +131 -131
  130. package/core/framework/index.ts +7 -7
  131. package/core/framework/server.ts +47 -40
  132. package/core/framework/types.ts +2 -2
  133. package/core/index.ts +23 -4
  134. package/core/live/ComponentRegistry.ts +3 -3
  135. package/core/live/types.ts +77 -0
  136. package/core/plugins/built-in/index.ts +134 -134
  137. package/core/plugins/built-in/live-components/commands/create-live-component.ts +242 -1066
  138. package/core/plugins/built-in/live-components/index.ts +1 -1
  139. package/core/plugins/built-in/monitoring/index.ts +111 -47
  140. package/core/plugins/built-in/static/index.ts +1 -1
  141. package/core/plugins/built-in/swagger/index.ts +68 -265
  142. package/core/plugins/built-in/vite/index.ts +85 -185
  143. package/core/plugins/built-in/vite/vite-dev.ts +10 -16
  144. package/core/plugins/config.ts +9 -7
  145. package/core/plugins/dependency-manager.ts +31 -1
  146. package/core/plugins/discovery.ts +19 -7
  147. package/core/plugins/executor.ts +2 -2
  148. package/core/plugins/index.ts +203 -203
  149. package/core/plugins/manager.ts +27 -39
  150. package/core/plugins/module-resolver.ts +19 -8
  151. package/core/plugins/registry.ts +255 -19
  152. package/core/plugins/types.ts +20 -53
  153. package/core/server/framework.ts +66 -43
  154. package/core/server/index.ts +15 -15
  155. package/core/server/live/ComponentRegistry.ts +78 -71
  156. package/core/server/live/FileUploadManager.ts +23 -10
  157. package/core/server/live/LiveComponentPerformanceMonitor.ts +1 -1
  158. package/core/server/live/LiveRoomManager.ts +261 -0
  159. package/core/server/live/RoomEventBus.ts +234 -0
  160. package/core/server/live/RoomStateManager.ts +172 -0
  161. package/core/server/live/StateSignature.ts +643 -643
  162. package/core/server/live/WebSocketConnectionManager.ts +30 -19
  163. package/core/server/live/auto-generated-components.ts +21 -9
  164. package/core/server/live/index.ts +14 -0
  165. package/core/server/live/websocket-plugin.ts +214 -67
  166. package/core/server/middleware/elysia-helpers.ts +7 -2
  167. package/core/server/middleware/errorHandling.ts +1 -1
  168. package/core/server/middleware/index.ts +31 -31
  169. package/core/server/plugins/database.ts +180 -180
  170. package/core/server/plugins/static-files-plugin.ts +69 -69
  171. package/core/server/plugins/swagger.ts +1 -1
  172. package/core/server/rooms/RoomBroadcaster.ts +357 -0
  173. package/core/server/rooms/RoomSystem.ts +463 -0
  174. package/core/server/rooms/index.ts +13 -0
  175. package/core/server/services/BaseService.ts +1 -1
  176. package/core/server/services/ServiceContainer.ts +1 -1
  177. package/core/server/services/index.ts +8 -8
  178. package/core/templates/create-project.ts +12 -12
  179. package/core/testing/index.ts +9 -9
  180. package/core/testing/setup.ts +73 -73
  181. package/core/types/api.ts +168 -168
  182. package/core/types/build.ts +219 -219
  183. package/core/types/config.ts +56 -26
  184. package/core/types/index.ts +4 -4
  185. package/core/types/plugin.ts +107 -107
  186. package/core/types/types.ts +353 -14
  187. package/core/utils/build-logger.ts +324 -324
  188. package/core/utils/config-schema.ts +480 -480
  189. package/core/utils/env.ts +2 -8
  190. package/core/utils/errors/codes.ts +114 -114
  191. package/core/utils/errors/handlers.ts +36 -1
  192. package/core/utils/errors/index.ts +49 -5
  193. package/core/utils/errors/middleware.ts +113 -113
  194. package/core/utils/helpers.ts +6 -16
  195. package/core/utils/index.ts +17 -17
  196. package/core/utils/logger/colors.ts +114 -114
  197. package/core/utils/logger/config.ts +13 -9
  198. package/core/utils/logger/formatter.ts +82 -82
  199. package/core/utils/logger/group-logger.ts +101 -101
  200. package/core/utils/logger/index.ts +6 -1
  201. package/core/utils/logger/stack-trace.ts +3 -1
  202. package/core/utils/logger/startup-banner.ts +82 -82
  203. package/core/utils/logger/winston-logger.ts +152 -152
  204. package/core/utils/monitoring/index.ts +211 -211
  205. package/core/utils/sync-version.ts +66 -66
  206. package/core/utils/version.ts +1 -1
  207. package/create-fluxstack.ts +8 -7
  208. package/package.json +12 -13
  209. package/plugins/crypto-auth/cli/make-protected-route.command.ts +1 -1
  210. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -302
  211. package/plugins/crypto-auth/client/components/index.ts +11 -11
  212. package/plugins/crypto-auth/client/index.ts +11 -11
  213. package/plugins/crypto-auth/config/index.ts +1 -1
  214. package/plugins/crypto-auth/index.ts +4 -4
  215. package/plugins/crypto-auth/package.json +65 -65
  216. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  217. package/plugins/crypto-auth/server/CryptoAuthService.ts +185 -185
  218. package/plugins/crypto-auth/server/index.ts +21 -21
  219. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +3 -3
  220. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +1 -1
  221. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +2 -2
  222. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +2 -2
  223. package/plugins/crypto-auth/server/middlewares/helpers.ts +1 -1
  224. package/plugins/crypto-auth/server/middlewares/index.ts +22 -22
  225. package/tsconfig.api-strict.json +16 -0
  226. package/tsconfig.json +48 -52
  227. package/{app/client/tsconfig.node.json → tsconfig.node.json} +25 -25
  228. package/types/global.d.ts +29 -29
  229. package/types/vitest.d.ts +8 -8
  230. package/vite.config.ts +38 -62
  231. package/vitest.config.live.ts +10 -9
  232. package/vitest.config.ts +29 -17
  233. package/app/client/README.md +0 -69
  234. package/app/client/SIMPLIFICATION.md +0 -140
  235. package/app/client/frontend-only.ts +0 -12
  236. package/app/client/src/live/FileUploadExample.tsx +0 -359
  237. package/app/client/src/live/MinimalLiveClock.tsx +0 -47
  238. package/app/client/src/live/QuickUploadTest.tsx +0 -193
  239. package/app/client/tsconfig.app.json +0 -45
  240. package/app/client/tsconfig.json +0 -7
  241. package/app/client/zustand-setup.md +0 -65
  242. package/app/server/backend-only.ts +0 -18
  243. package/app/server/live/LiveClockComponent.ts +0 -215
  244. package/app/server/live/LiveFileUploadComponent.ts +0 -77
  245. package/app/server/routes/env-test.ts +0 -110
  246. package/core/client/hooks/index.ts +0 -7
  247. package/core/client/hooks/useHybridLiveComponent.ts +0 -685
  248. package/core/client/hooks/useTypedLiveComponent.ts +0 -133
  249. package/core/client/hooks/useWebSocket.ts +0 -361
  250. package/core/config/env.ts +0 -546
  251. package/core/config/loader.ts +0 -522
  252. package/core/config/runtime-config.ts +0 -327
  253. package/core/config/validator.ts +0 -540
  254. package/core/server/backend-entry.ts +0 -51
  255. package/core/server/standalone.ts +0 -106
  256. package/core/utils/regenerate-files.ts +0 -69
  257. package/fluxstack.config.ts +0 -354
@@ -0,0 +1,81 @@
1
+ // LiveUpload - Estado de upload chunked + sincronização UI
2
+
3
+ import { LiveComponent } from '@core/types/types'
4
+
5
+ // Componente Cliente (Ctrl+Click para navegar)
6
+ import type { UploadDemo as _Client } from '@client/src/live/UploadDemo'
7
+
8
+ export class LiveUpload extends LiveComponent<typeof LiveUpload.defaultState> {
9
+ static componentName = 'LiveUpload'
10
+ static defaultState = {
11
+ status: 'idle' as 'idle' | 'uploading' | 'complete' | 'error',
12
+ progress: 0,
13
+ fileName: '',
14
+ fileSize: 0,
15
+ fileType: '',
16
+ fileUrl: '',
17
+ bytesUploaded: 0,
18
+ totalBytes: 0,
19
+ error: null as string | null
20
+ }
21
+
22
+ async startUpload(payload: { fileName: string; fileSize: number; fileType: string }) {
23
+ const normalized = payload.fileName.toLowerCase()
24
+ if (normalized.includes('..') || normalized.includes('/') || normalized.includes('\\')) {
25
+ throw new Error('Invalid file name')
26
+ }
27
+
28
+ // All file types allowed - no extension blocking
29
+ // Security note: Configure allowed extensions per your application needs
30
+
31
+ this.setState({
32
+ status: 'uploading',
33
+ progress: 0,
34
+ fileName: payload.fileName,
35
+ fileSize: payload.fileSize,
36
+ fileType: payload.fileType,
37
+ fileUrl: '',
38
+ bytesUploaded: 0,
39
+ totalBytes: payload.fileSize,
40
+ error: null
41
+ })
42
+
43
+ return { success: true }
44
+ }
45
+
46
+ async updateProgress(payload: { progress: number; bytesUploaded: number; totalBytes: number }) {
47
+ const progress = Math.max(0, Math.min(100, payload.progress))
48
+ this.setState({
49
+ progress,
50
+ bytesUploaded: payload.bytesUploaded,
51
+ totalBytes: payload.totalBytes
52
+ })
53
+
54
+ return { success: true, progress }
55
+ }
56
+
57
+ async completeUpload(payload: { fileUrl: string }) {
58
+ this.setState({
59
+ status: 'complete',
60
+ progress: 100,
61
+ fileUrl: payload.fileUrl,
62
+ error: null
63
+ })
64
+
65
+ return { success: true }
66
+ }
67
+
68
+ async failUpload(payload: { error: string }) {
69
+ this.setState({
70
+ status: 'error',
71
+ error: payload.error || 'Upload failed'
72
+ })
73
+
74
+ return { success: true }
75
+ }
76
+
77
+ async reset() {
78
+ this.setState({ ...LiveUpload.defaultState })
79
+ return { success: true }
80
+ }
81
+ }
@@ -1,5 +1,6 @@
1
1
  import { Elysia, t } from "elysia"
2
2
  import { usersRoutes } from "./users.routes"
3
+ import { roomRoutes } from "./room.routes"
3
4
 
4
5
  export const apiRoutes = new Elysia({ prefix: "/api" })
5
6
  .get("/", () => ({ message: "🔥 Hot Reload funcionando! FluxStack API v1.4.0 ⚡" }), {
@@ -32,5 +33,6 @@ export const apiRoutes = new Elysia({ prefix: "/api" })
32
33
  description: 'Returns the current health status of the API server'
33
34
  }
34
35
  })
35
- // Register users routes
36
+ // Register routes
36
37
  .use(usersRoutes)
38
+ .use(roomRoutes)
@@ -0,0 +1,117 @@
1
+ // 🔥 Room API Routes - Enviar mensagens para salas via HTTP
2
+ //
3
+ // Permite que sistemas externos (webhooks, outros serviços, etc)
4
+ // enviem mensagens para salas de chat via API REST
5
+
6
+ import { Elysia, t } from 'elysia'
7
+ import { liveRoomManager } from '@core/server/live/LiveRoomManager'
8
+ import { roomEvents } from '@core/server/live/RoomEventBus'
9
+
10
+ export const roomRoutes = new Elysia({ prefix: '/rooms' })
11
+
12
+ // Enviar mensagem para uma sala
13
+ .post('/:roomId/messages', ({ params, body }) => {
14
+ const { roomId } = params
15
+ const { user, text } = body
16
+
17
+ const message = {
18
+ id: `api-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
19
+ user: user || 'API Bot',
20
+ text,
21
+ timestamp: Date.now()
22
+ }
23
+
24
+ // Emitir evento para a sala
25
+ // Isso vai:
26
+ // 1. Notificar handlers server-side via roomEvents
27
+ // 2. Broadcast via WebSocket para frontends
28
+ const notified = liveRoomManager.emitToRoom(roomId, 'message:new', message)
29
+
30
+ return {
31
+ success: true,
32
+ message,
33
+ notified,
34
+ roomId
35
+ }
36
+ }, {
37
+ params: t.Object({
38
+ roomId: t.String({ description: 'ID da sala (ex: geral, tech, random)' })
39
+ }),
40
+ body: t.Object({
41
+ user: t.Optional(t.String({ description: 'Nome do usuário (opcional, default: API Bot)' })),
42
+ text: t.String({ description: 'Texto da mensagem', minLength: 1, maxLength: 1000 })
43
+ }),
44
+ response: t.Object({
45
+ success: t.Boolean(),
46
+ message: t.Object({
47
+ id: t.String(),
48
+ user: t.String(),
49
+ text: t.String(),
50
+ timestamp: t.Number()
51
+ }),
52
+ notified: t.Number(),
53
+ roomId: t.String()
54
+ }),
55
+ detail: {
56
+ tags: ['Rooms'],
57
+ summary: 'Enviar mensagem para sala',
58
+ description: 'Envia uma mensagem para todos os usuários conectados em uma sala específica'
59
+ }
60
+ })
61
+
62
+ // Emitir evento customizado para uma sala
63
+ .post('/:roomId/emit', ({ params, body }) => {
64
+ const { roomId } = params
65
+ const { event, data } = body
66
+
67
+ const notified = liveRoomManager.emitToRoom(roomId, event, data)
68
+
69
+ return {
70
+ success: true,
71
+ event,
72
+ notified,
73
+ roomId
74
+ }
75
+ }, {
76
+ params: t.Object({
77
+ roomId: t.String({ description: 'ID da sala' })
78
+ }),
79
+ body: t.Object({
80
+ event: t.String({ description: 'Nome do evento (ex: user:typing, notification)' }),
81
+ data: t.Any({ description: 'Dados do evento' })
82
+ }),
83
+ response: t.Object({
84
+ success: t.Boolean(),
85
+ event: t.String(),
86
+ notified: t.Number(),
87
+ roomId: t.String()
88
+ }),
89
+ detail: {
90
+ tags: ['Rooms'],
91
+ summary: 'Emitir evento customizado',
92
+ description: 'Emite um evento customizado para todos os componentes em uma sala'
93
+ }
94
+ })
95
+
96
+ // Obter estatísticas das salas
97
+ .get('/stats', () => {
98
+ const roomStats = liveRoomManager.getStats()
99
+ const eventStats = roomEvents.getStats()
100
+
101
+ return {
102
+ success: true,
103
+ rooms: roomStats,
104
+ events: eventStats
105
+ }
106
+ }, {
107
+ response: t.Object({
108
+ success: t.Boolean(),
109
+ rooms: t.Any(),
110
+ events: t.Any()
111
+ }),
112
+ detail: {
113
+ tags: ['Rooms'],
114
+ summary: 'Estatísticas das salas',
115
+ description: 'Retorna estatísticas sobre salas ativas e eventos registrados'
116
+ }
117
+ })
@@ -1,5 +1,6 @@
1
1
  import { Elysia, t } from 'elysia'
2
- import { UsersController } from '@/app/server/controllers/users.controller'
2
+ import { UsersController } from '@app/server/controllers/users.controller'
3
+ import type { CreateUserRequest } from '@app/shared/types'
3
4
 
4
5
  // ===== Request/Response Schemas =====
5
6
 
@@ -77,9 +78,7 @@ const ErrorResponseSchema = t.Object({
77
78
  */
78
79
  export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
79
80
  // GET /users - Get all users
80
- .get('/', async () => {
81
- return await UsersController.getUsers()
82
- }, {
81
+ .get('/', async () => UsersController.getUsers(), {
83
82
  detail: {
84
83
  summary: 'Get All Users',
85
84
  description: 'Retrieves a list of all registered users',
@@ -90,19 +89,18 @@ export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
90
89
 
91
90
  // GET /users/:id - Get user by ID
92
91
  .get('/:id', async ({ params, set }) => {
93
- const id = parseInt(params.id)
92
+ const id = Number(params.id)
94
93
 
95
- // Handle invalid ID
96
- if (isNaN(id)) {
94
+ if (!Number.isFinite(id)) {
97
95
  set.status = 400
98
- return { error: 'ID inválido' }
96
+ return { success: false, error: 'ID invalido' }
99
97
  }
100
98
 
101
99
  const result = await UsersController.getUserById(id)
102
100
 
103
- if (!result) {
101
+ if (!result.success) {
104
102
  set.status = 404
105
- return { error: 'Usuário não encontrado' }
103
+ return result
106
104
  }
107
105
 
108
106
  return result
@@ -124,17 +122,17 @@ export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
124
122
 
125
123
  // POST /users - Create new user
126
124
  .post('/', async ({ body, set }) => {
127
- // Validate required fields
128
- if (!body.name || !body.email) {
125
+ const payload = body as CreateUserRequest
126
+
127
+ if (!payload.name || !payload.email) {
129
128
  set.status = 400
130
129
  return {
131
130
  success: false,
132
- error: 'Nome e email são obrigatórios'
131
+ error: 'Nome e email sao obrigatorios'
133
132
  }
134
133
  }
135
134
 
136
- // Validate name length
137
- if (body.name.length < 2) {
135
+ if (payload.name.trim().length < 2) {
138
136
  set.status = 400
139
137
  return {
140
138
  success: false,
@@ -142,23 +140,28 @@ export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
142
140
  }
143
141
  }
144
142
 
145
- // Validate email format
146
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
147
- if (!emailRegex.test(body.email)) {
143
+ const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/
144
+ if (!emailRegex.test(payload.email)) {
148
145
  set.status = 400
149
146
  return {
150
147
  success: false,
151
- error: 'Email inválido'
148
+ error: 'Email invalido'
152
149
  }
153
150
  }
154
151
 
155
- const result = await UsersController.createUser(body)
152
+ const sanitizedPayload: CreateUserRequest = {
153
+ name: payload.name.trim(),
154
+ email: payload.email.trim()
155
+ }
156
+
157
+ const result = await UsersController.createUser(sanitizedPayload)
156
158
 
157
- // If email is duplicate, still return 200 but with success: false
158
159
  if (!result.success) {
160
+ set.status = 409
159
161
  return result
160
162
  }
161
163
 
164
+ set.status = 201
162
165
  return result
163
166
  }, {
164
167
  detail: {
@@ -168,30 +171,34 @@ export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
168
171
  },
169
172
  body: CreateUserRequestSchema,
170
173
  response: {
171
- 200: CreateUserResponseSchema,
174
+ 201: CreateUserResponseSchema,
172
175
  400: t.Object({
173
176
  success: t.Literal(false),
174
177
  error: t.String()
178
+ }),
179
+ 409: t.Object({
180
+ success: t.Literal(false),
181
+ error: t.String()
175
182
  })
176
183
  }
177
184
  })
178
185
 
179
186
  // DELETE /users/:id - Delete user
180
187
  .delete('/:id', async ({ params, set }) => {
181
- const id = parseInt(params.id)
188
+ const id = Number(params.id)
182
189
 
183
- if (isNaN(id)) {
190
+ if (!Number.isFinite(id)) {
184
191
  set.status = 400
185
192
  return {
186
193
  success: false,
187
- message: 'ID inválido'
194
+ message: 'ID invalido'
188
195
  }
189
196
  }
190
197
 
191
198
  const result = await UsersController.deleteUser(id)
192
199
 
193
200
  if (!result.success) {
194
- // Don't set 404 status, just return success: false
201
+ set.status = 404
195
202
  return result
196
203
  }
197
204
 
@@ -210,6 +217,7 @@ export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
210
217
  400: t.Object({
211
218
  success: t.Literal(false),
212
219
  message: t.String()
213
- })
220
+ }),
221
+ 404: DeleteUserResponseSchema
214
222
  }
215
223
  })
@@ -11,8 +11,20 @@ export interface CreateUserRequest {
11
11
  email: string
12
12
  }
13
13
 
14
- export interface UserResponse {
14
+ export interface UserListResponse {
15
+ success: true
16
+ users: User[]
17
+ count: number
18
+ }
19
+
20
+ export interface UserDetailResponse {
15
21
  success: boolean
16
22
  user?: User
23
+ error?: string
24
+ }
25
+
26
+ export interface MutationResponse {
27
+ success: boolean
17
28
  message?: string
18
- }
29
+ error?: string
30
+ }
@@ -1,62 +1,2 @@
1
- /**
2
- * Application Configuration
3
- * Core application metadata and global settings
4
- */
5
-
6
- import { defineConfig, config } from '@/core/utils/config-schema'
7
- import { FLUXSTACK_VERSION } from '@/core/utils/version'
8
-
9
- /**
10
- * App configuration schema
11
- * Contains only app-level metadata and global feature flags
12
- */
13
- const appConfigSchema = {
14
- // App basics
15
- name: config.string('APP_NAME', 'FluxStack', true),
16
-
17
- version: {
18
- type: 'string' as const,
19
- env: 'APP_VERSION',
20
- default: FLUXSTACK_VERSION,
21
- validate: (value: string) => /^\d+\.\d+\.\d+$/.test(value) || 'Version must be semver format (e.g., 1.0.0)'
22
- },
23
-
24
- description: config.string('APP_DESCRIPTION', 'A FluxStack application'),
25
-
26
- // Environment
27
- env: config.enum('NODE_ENV', ['development', 'production', 'test'] as const, 'development', true),
28
-
29
- // URLs
30
- url: config.string('APP_URL', undefined, false),
31
-
32
- // Security
33
- trustProxy: config.boolean('TRUST_PROXY', false),
34
-
35
- sessionSecret: {
36
- type: 'string' as const,
37
- env: 'SESSION_SECRET',
38
- default: undefined,
39
- required: false,
40
- validate: (value: string) => {
41
- if (!value) return true // Optional
42
- if (value.length < 32) {
43
- return 'Session secret must be at least 32 characters'
44
- }
45
- return true
46
- }
47
- }
48
- } as const
49
-
50
- export const appConfig = defineConfig(appConfigSchema)
51
-
52
- // Export type for use in other files
53
- export type AppConfig = typeof appConfig
54
-
55
- /**
56
- * Type-safe environment type
57
- * Use this when you need the literal type explicitly
58
- */
59
- export type Environment = typeof appConfig.env
60
-
61
- // Export default
62
- export default appConfig
1
+ export { appConfig as default, appConfig } from './system/app.config'
2
+ export type { AppConfig } from './system/app.config'
@@ -1,95 +1,2 @@
1
- /**
2
- * Client & Vite Configuration
3
- * Declarative client, proxy and Vite dev server configuration
4
- */
5
-
6
- import { defineConfig, defineNestedConfig, config } from '@/core/utils/config-schema'
7
- import { env, helpers } from '@/core/utils/env'
8
-
9
- /**
10
- * Vite Dev Server Configuration
11
- */
12
- const viteSchema = {
13
- port: config.number('VITE_PORT', 5173, true),
14
-
15
- host: config.string('VITE_HOST', 'localhost'),
16
-
17
- strictPort: config.boolean('VITE_STRICT_PORT', false),
18
-
19
- open: config.boolean('VITE_OPEN', false),
20
-
21
- enableLogging: config.boolean('ENABLE_VITE_PROXY_LOGS', false)
22
- } as const
23
-
24
- /**
25
- * API Proxy Configuration
26
- */
27
- const proxySchema = {
28
- target: {
29
- type: 'string' as const,
30
- env: 'PROXY_TARGET',
31
- default: helpers.getServerUrl(),
32
- required: false,
33
- validate: (value: string) => {
34
- if (!value) return true
35
- try {
36
- new URL(value)
37
- return true
38
- } catch {
39
- return 'Proxy target must be a valid URL'
40
- }
41
- }
42
- },
43
-
44
- changeOrigin: config.boolean('PROXY_CHANGE_ORIGIN', true),
45
-
46
- secure: config.boolean('PROXY_SECURE', false),
47
-
48
- ws: config.boolean('PROXY_WS', true), // WebSocket support
49
-
50
- rewrite: {
51
- type: 'object' as const,
52
- env: 'PROXY_REWRITE',
53
- default: {},
54
- required: false
55
- }
56
- } as const
57
-
58
- /**
59
- * Client Build Configuration
60
- */
61
- const buildSchema = {
62
- outDir: config.string('CLIENT_OUTDIR', 'dist/client'),
63
-
64
- sourceMaps: config.boolean('CLIENT_SOURCEMAPS', helpers.isDevelopment()),
65
-
66
- minify: config.boolean('CLIENT_MINIFY', helpers.isProduction()),
67
-
68
- target: config.string('CLIENT_TARGET', 'esnext'),
69
-
70
- assetsDir: config.string('CLIENT_ASSETS_DIR', 'assets'),
71
-
72
- cssCodeSplit: config.boolean('CLIENT_CSS_CODE_SPLIT', true),
73
-
74
- chunkSizeWarningLimit: config.number('CLIENT_CHUNK_SIZE_WARNING', 500), // KB
75
-
76
- emptyOutDir: config.boolean('CLIENT_EMPTY_OUTDIR', true)
77
- } as const
78
-
79
- /**
80
- * Client Configuration (nested)
81
- */
82
- export const clientConfig = defineNestedConfig({
83
- vite: viteSchema,
84
- proxy: proxySchema,
85
- build: buildSchema
86
- })
87
-
88
- // Export types
89
- export type ViteConfig = typeof clientConfig.vite
90
- export type ProxyConfig = typeof clientConfig.proxy
91
- export type ClientBuildConfig = typeof clientConfig.build
92
- export type ClientConfig = typeof clientConfig
93
-
94
- // Export default
95
- export default clientConfig
1
+ export { clientConfig as default, clientConfig } from './system/client.config'
2
+ export type { ClientConfig, ViteConfig, ClientBuildConfig } from './system/client.config'
@@ -1,99 +1,2 @@
1
- /**
2
- * Database Configuration
3
- * Laravel-style declarative config with validation
4
- */
5
-
6
- import { defineConfig, config } from '@/core/utils/config-schema'
7
-
8
- /**
9
- * Database configuration schema
10
- */
11
- export const databaseConfig = defineConfig({
12
- // Connection
13
- url: {
14
- type: 'string',
15
- env: 'DATABASE_URL',
16
- default: undefined,
17
- required: false,
18
- validate: (value) => {
19
- if (!value) return true // Optional
20
- if (!value.includes('://')) {
21
- return 'DATABASE_URL must be a valid connection string (e.g., postgres://...)'
22
- }
23
- return true
24
- },
25
- description: 'Full database connection URL (overrides individual settings)'
26
- },
27
-
28
- host: config.string('DB_HOST', 'localhost'),
29
-
30
- port: config.number('DB_PORT', 5432),
31
-
32
- database: {
33
- type: 'string',
34
- env: 'DB_NAME',
35
- default: undefined,
36
- required: false,
37
- description: 'Database name'
38
- },
39
-
40
- user: {
41
- type: 'string',
42
- env: 'DB_USER',
43
- default: undefined,
44
- required: false
45
- },
46
-
47
- password: {
48
- type: 'string',
49
- env: 'DB_PASSWORD',
50
- default: undefined,
51
- required: false
52
- },
53
-
54
- // Connection pool
55
- poolMin: {
56
- type: 'number',
57
- env: 'DB_POOL_MIN',
58
- default: 2,
59
- validate: (value) => value >= 0 || 'Pool min must be >= 0'
60
- },
61
-
62
- poolMax: {
63
- type: 'number',
64
- env: 'DB_POOL_MAX',
65
- default: 10,
66
- validate: (value) => value > 0 || 'Pool max must be > 0'
67
- },
68
-
69
- // SSL
70
- ssl: config.boolean('DB_SSL', false),
71
-
72
- // Timeouts
73
- connectionTimeout: {
74
- type: 'number',
75
- env: 'DB_CONNECTION_TIMEOUT',
76
- default: 30000,
77
- description: 'Connection timeout in milliseconds'
78
- },
79
-
80
- queryTimeout: {
81
- type: 'number',
82
- env: 'DB_QUERY_TIMEOUT',
83
- default: 60000,
84
- description: 'Query timeout in milliseconds'
85
- },
86
-
87
- // Features
88
- enableLogging: config.boolean('DB_ENABLE_LOGGING', false),
89
-
90
- enableMigrations: config.boolean('DB_ENABLE_MIGRATIONS', true),
91
-
92
- migrationsTable: config.string('DB_MIGRATIONS_TABLE', 'migrations')
93
- })
94
-
95
- // Export type
96
- export type DatabaseConfig = typeof databaseConfig
97
-
98
- // Export default
99
- export default databaseConfig
1
+ export { databaseConfig as default, databaseConfig } from './system/database.config'
2
+ export type { DatabaseConfig } from './system/database.config'