create-fluxstack 1.7.5 → 1.8.3

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 (154) hide show
  1. package/.dockerignore +82 -0
  2. package/.env.example +19 -0
  3. package/Dockerfile +70 -0
  4. package/README.md +6 -3
  5. package/app/client/SIMPLIFICATION.md +140 -0
  6. package/app/client/frontend-only.ts +1 -1
  7. package/app/client/src/App.tsx +148 -283
  8. package/app/client/src/index.css +5 -20
  9. package/app/client/src/lib/eden-api.ts +53 -220
  10. package/app/client/src/main.tsx +2 -3
  11. package/app/server/app.ts +20 -5
  12. package/app/server/backend-only.ts +15 -12
  13. package/app/server/controllers/users.controller.ts +57 -31
  14. package/app/server/index.ts +86 -96
  15. package/app/server/live/register-components.ts +18 -7
  16. package/app/server/routes/env-test.ts +110 -0
  17. package/app/server/routes/index.ts +1 -8
  18. package/app/server/routes/users.routes.ts +192 -91
  19. package/config/app.config.ts +2 -54
  20. package/config/client.config.ts +95 -0
  21. package/config/fluxstack.config.ts +2 -2
  22. package/config/index.ts +57 -22
  23. package/config/monitoring.config.ts +114 -0
  24. package/config/plugins.config.ts +80 -0
  25. package/config/runtime.config.ts +0 -17
  26. package/config/server.config.ts +50 -30
  27. package/core/build/bundler.ts +17 -16
  28. package/core/build/flux-plugins-generator.ts +34 -23
  29. package/core/build/index.ts +32 -31
  30. package/core/build/live-components-generator.ts +44 -30
  31. package/core/build/optimizer.ts +37 -17
  32. package/core/cli/command-registry.ts +4 -14
  33. package/core/cli/commands/plugin-deps.ts +8 -8
  34. package/core/cli/generators/component.ts +3 -3
  35. package/core/cli/generators/controller.ts +4 -4
  36. package/core/cli/generators/index.ts +8 -8
  37. package/core/cli/generators/interactive.ts +4 -4
  38. package/core/cli/generators/plugin.ts +3 -3
  39. package/core/cli/generators/prompts.ts +1 -1
  40. package/core/cli/generators/route.ts +27 -11
  41. package/core/cli/generators/service.ts +5 -5
  42. package/core/cli/generators/template-engine.ts +1 -1
  43. package/core/cli/generators/types.ts +1 -1
  44. package/core/cli/index.ts +158 -189
  45. package/core/cli/plugin-discovery.ts +3 -3
  46. package/core/client/hooks/index.ts +2 -2
  47. package/core/client/hooks/state-validator.ts +1 -1
  48. package/core/client/hooks/useAuth.ts +1 -1
  49. package/core/client/hooks/useChunkedUpload.ts +1 -1
  50. package/core/client/hooks/useHybridLiveComponent.ts +1 -1
  51. package/core/client/hooks/useWebSocket.ts +1 -1
  52. package/core/config/env.ts +5 -1
  53. package/core/config/runtime-config.ts +12 -10
  54. package/core/config/schema.ts +33 -2
  55. package/core/framework/server.ts +30 -14
  56. package/core/framework/types.ts +2 -2
  57. package/core/index.ts +31 -23
  58. package/core/live/ComponentRegistry.ts +1 -1
  59. package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
  60. package/core/plugins/built-in/live-components/index.ts +1 -1
  61. package/core/plugins/built-in/monitoring/index.ts +65 -161
  62. package/core/plugins/built-in/static/index.ts +75 -277
  63. package/core/plugins/built-in/swagger/index.ts +301 -231
  64. package/core/plugins/built-in/vite/index.ts +342 -377
  65. package/core/plugins/config.ts +2 -2
  66. package/core/plugins/dependency-manager.ts +2 -2
  67. package/core/plugins/discovery.ts +1 -1
  68. package/core/plugins/executor.ts +2 -2
  69. package/core/plugins/manager.ts +19 -4
  70. package/core/plugins/module-resolver.ts +1 -1
  71. package/core/plugins/registry.ts +25 -21
  72. package/core/plugins/types.ts +147 -5
  73. package/core/server/backend-entry.ts +51 -0
  74. package/core/server/framework.ts +2 -2
  75. package/core/server/live/ComponentRegistry.ts +9 -26
  76. package/core/server/live/FileUploadManager.ts +1 -1
  77. package/core/server/live/auto-generated-components.ts +26 -0
  78. package/core/server/live/websocket-plugin.ts +211 -19
  79. package/core/server/middleware/errorHandling.ts +1 -1
  80. package/core/server/middleware/index.ts +4 -4
  81. package/core/server/plugins/database.ts +1 -2
  82. package/core/server/plugins/static-files-plugin.ts +259 -231
  83. package/core/server/plugins/swagger.ts +1 -1
  84. package/core/server/services/BaseService.ts +1 -1
  85. package/core/server/services/ServiceContainer.ts +1 -1
  86. package/core/server/services/index.ts +4 -4
  87. package/core/server/standalone.ts +16 -1
  88. package/core/testing/index.ts +1 -1
  89. package/core/testing/setup.ts +1 -1
  90. package/core/types/plugin.ts +6 -0
  91. package/core/utils/build-logger.ts +324 -0
  92. package/core/utils/config-schema.ts +2 -6
  93. package/core/utils/helpers.ts +14 -9
  94. package/core/utils/logger/startup-banner.ts +7 -33
  95. package/core/utils/regenerate-files.ts +69 -0
  96. package/core/utils/version.ts +6 -6
  97. package/create-fluxstack.ts +68 -25
  98. package/fluxstack.config.ts +138 -252
  99. package/package.json +3 -18
  100. package/plugins/crypto-auth/index.ts +52 -47
  101. package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
  102. package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
  103. package/vitest.config.ts +17 -26
  104. package/app/client/src/App.css +0 -883
  105. package/app/client/src/components/ErrorBoundary.tsx +0 -107
  106. package/app/client/src/components/ErrorDisplay.css +0 -365
  107. package/app/client/src/components/ErrorDisplay.tsx +0 -258
  108. package/app/client/src/components/FluxStackConfig.tsx +0 -1321
  109. package/app/client/src/components/HybridLiveCounter.tsx +0 -140
  110. package/app/client/src/components/LiveClock.tsx +0 -286
  111. package/app/client/src/components/MainLayout.tsx +0 -388
  112. package/app/client/src/components/SidebarNavigation.tsx +0 -391
  113. package/app/client/src/components/StateDemo.tsx +0 -178
  114. package/app/client/src/components/SystemMonitor.tsx +0 -1044
  115. package/app/client/src/components/UserProfile.tsx +0 -809
  116. package/app/client/src/hooks/useAuth.ts +0 -39
  117. package/app/client/src/hooks/useNotifications.ts +0 -56
  118. package/app/client/src/lib/errors.ts +0 -340
  119. package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
  120. package/app/client/src/lib/index.ts +0 -45
  121. package/app/client/src/pages/ApiDocs.tsx +0 -182
  122. package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
  123. package/app/client/src/pages/Demo.tsx +0 -174
  124. package/app/client/src/pages/HybridLive.tsx +0 -263
  125. package/app/client/src/pages/Overview.tsx +0 -155
  126. package/app/client/src/store/README.md +0 -43
  127. package/app/client/src/store/index.ts +0 -16
  128. package/app/client/src/store/slices/uiSlice.ts +0 -151
  129. package/app/client/src/store/slices/userSlice.ts +0 -161
  130. package/app/client/src/test/README.md +0 -257
  131. package/app/client/src/test/setup.ts +0 -70
  132. package/app/client/src/test/types.ts +0 -12
  133. package/app/server/live/CounterComponent.ts +0 -191
  134. package/app/server/live/FluxStackConfig.ts +0 -534
  135. package/app/server/live/SidebarNavigation.ts +0 -157
  136. package/app/server/live/SystemMonitor.ts +0 -595
  137. package/app/server/live/SystemMonitorIntegration.ts +0 -151
  138. package/app/server/live/UserProfileComponent.ts +0 -141
  139. package/app/server/middleware/auth.ts +0 -136
  140. package/app/server/middleware/errorHandling.ts +0 -252
  141. package/app/server/middleware/index.ts +0 -10
  142. package/app/server/middleware/rateLimit.ts +0 -193
  143. package/app/server/middleware/requestLogging.ts +0 -215
  144. package/app/server/middleware/validation.ts +0 -270
  145. package/app/server/routes/config.ts +0 -145
  146. package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
  147. package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
  148. package/app/server/routes/exemplo-posts.routes.ts +0 -161
  149. package/app/server/routes/upload.ts +0 -92
  150. package/app/server/services/NotificationService.ts +0 -302
  151. package/app/server/services/UserService.ts +0 -222
  152. package/app/server/services/index.ts +0 -46
  153. package/app/server/types/index.ts +0 -1
  154. package/config/build.config.ts +0 -24
@@ -1,125 +1,115 @@
1
- // User application entry point
2
- import { FluxStackFramework, vitePlugin, swaggerPlugin, staticPlugin, liveComponentsPlugin, staticFilesPlugin } from "@/core/server"
1
+ /**
2
+ * 🚀 FluxStack Application Server Entry Point
3
+ * Main server configuration and initialization
4
+ */
5
+
6
+ // ===== Core Framework =====
7
+ import { FluxStackFramework } from "@/core/server"
3
8
  import { isDevelopment } from "@/core/utils/helpers"
4
9
  import { DEBUG } from "@/core/utils/logger"
5
- import { apiRoutes } from "./routes"
6
10
  import { helpers } from "@/core/utils/env"
7
- import { serverConfig } from "@/config/server.config"
11
+
12
+ // ===== Configuration =====
8
13
  import { appConfig } from "@/config/app.config"
9
- import { loggerConfig } from "@/config/logger.config"
14
+ import { serverConfig } from "@/config/server.config"
15
+
16
+ // ===== Plugins =====
17
+ import {
18
+ vitePlugin,
19
+ swaggerPlugin,
20
+ staticPlugin,
21
+ liveComponentsPlugin,
22
+ staticFilesPlugin
23
+ } from "@/core/server"
10
24
  import cryptoAuthPlugin from "@/plugins/crypto-auth"
11
- import "./live/register-components"
12
25
 
13
- // Startup info moved to DEBUG level (set LOG_LEVEL=debug to see details)
26
+ // ===== Application Routes =====
27
+ import { appInstance } from "./app"
28
+
29
+ // ===== Live Components Registration =====
30
+ // Import auto-generated component registrations from core/ (for production build)
31
+ // The generator creates this file in core/ to prevent accidental user modifications
32
+ // This ensures components are registered before the plugin tries to use them
33
+ import "@/core/server/live/auto-generated-components"
34
+
35
+ // ===== Startup Logging =====
14
36
  DEBUG('🔧 Loading declarative configuration...')
15
37
  DEBUG(`📊 Environment: ${appConfig.env}`)
16
- DEBUG(`🚀 Port: ${serverConfig.port}`)
17
- DEBUG(`🌐 Host: ${serverConfig.host}`)
18
-
19
- // Criar aplicação com configuração declarativa
20
- const app = new FluxStackFramework({
21
- server: {
22
- port: serverConfig.port,
23
- host: serverConfig.host,
24
- apiPrefix: serverConfig.apiPrefix,
25
- cors: {
26
- origins: serverConfig.corsOrigins,
27
- methods: serverConfig.corsMethods,
28
- headers: serverConfig.corsHeaders,
29
- credentials: serverConfig.corsCredentials
38
+ DEBUG(`🚀 Port: ${serverConfig.server.port}`)
39
+ DEBUG(`🌐 Host: ${serverConfig.server.host}`)
40
+
41
+ // ===== Framework Configuration Helper =====
42
+ /**
43
+ * Creates FluxStack framework configuration from declarative configs
44
+ */
45
+ function createFrameworkConfig() {
46
+ return {
47
+ server: {
48
+ port: serverConfig.server.port,
49
+ host: serverConfig.server.host,
50
+ apiPrefix: serverConfig.server.apiPrefix,
51
+ cors: {
52
+ origins: serverConfig.cors.origins,
53
+ methods: serverConfig.cors.methods,
54
+ headers: serverConfig.cors.headers,
55
+ credentials: serverConfig.cors.credentials
56
+ },
57
+ middleware: []
30
58
  },
31
- middleware: []
32
- },
33
- app: {
34
- name: serverConfig.appName,
35
- version: serverConfig.appVersion
36
- },
37
- client: {
38
- port: serverConfig.clientPort,
39
- proxy: {
40
- target: helpers.getServerUrl()
59
+ app: {
60
+ name: appConfig.name,
61
+ version: appConfig.version
41
62
  },
42
- build: {
43
- sourceMaps: serverConfig.clientSourceMaps,
44
- minify: false,
45
- target: serverConfig.clientTarget as any,
46
- outDir: serverConfig.clientOutDir
63
+ client: {
64
+ port: serverConfig.server.backendPort,
65
+ proxy: {
66
+ target: helpers.getServerUrl()
67
+ },
68
+ build: {
69
+ sourceMaps: false,
70
+ minify: false,
71
+ target: 'es2020' as any,
72
+ outDir: 'dist'
73
+ }
47
74
  }
48
75
  }
49
- })
76
+ }
50
77
 
78
+ // ===== Initialize Application =====
79
+ const app = new FluxStackFramework(createFrameworkConfig())
51
80
 
52
- // Usar plugins de infraestrutura primeiro (Logger é core, não é plugin)
81
+ // ===== Register Plugins =====
82
+ // Note: Logger is part of core, not a plugin
53
83
 
54
- // Registrar plugin de autenticação ANTES dos outros plugins
84
+ // 1. Authentication plugin (must be registered first)
55
85
  app.use(cryptoAuthPlugin)
56
86
 
57
- // Usar plugins condicionalmente baseado no ambiente
87
+ // 2. Development/Production plugins (conditional)
58
88
  if (isDevelopment()) {
59
- app.use(vitePlugin)
89
+ app.use(vitePlugin) // Development: Vite dev server
60
90
  } else {
61
- app.use(staticPlugin)
91
+ app.use(staticPlugin) // Production: Static file serving
62
92
  }
63
93
 
64
- // Add static files AFTER Vite to avoid conflicts, but BEFORE Live Components
65
- app.use(staticFilesPlugin) // Add Static Files support
66
- app.use(liveComponentsPlugin) // Add Live Components support
67
-
94
+ // 3. Static files (after Vite, before Live Components to avoid conflicts)
95
+ app.use(staticFilesPlugin)
68
96
 
69
- // Adicionar rota de teste para mostrar config declarativo (antes das rotas)
70
- app.getApp().get('/api/env-test', () => {
71
- return {
72
- message: '⚡ Declarative Config System!',
73
- timestamp: new Date().toISOString(),
74
- serverConfig: {
75
- port: serverConfig.port,
76
- host: serverConfig.host,
77
- apiPrefix: serverConfig.apiPrefix,
78
- appName: serverConfig.appName,
79
- appVersion: serverConfig.appVersion,
80
- cors: {
81
- origins: serverConfig.corsOrigins,
82
- methods: serverConfig.corsMethods,
83
- credentials: serverConfig.corsCredentials
84
- },
85
- client: {
86
- port: serverConfig.clientPort,
87
- target: serverConfig.clientTarget,
88
- sourceMaps: serverConfig.clientSourceMaps
89
- },
90
- features: {
91
- enableSwagger: serverConfig.enableSwagger,
92
- enableMetrics: serverConfig.enableMetrics,
93
- enableMonitoring: serverConfig.enableMonitoring
94
- }
95
- },
96
- environment: {
97
- NODE_ENV: appConfig.env,
98
- DEBUG: appConfig.debug,
99
- LOG_LEVEL: loggerConfig.level
100
- },
101
- urls: {
102
- server: helpers.getServerUrl(),
103
- client: helpers.getClientUrl(),
104
- swagger: `${helpers.getServerUrl()}/swagger`
105
- },
106
- system: {
107
- version: 'declarative-config',
108
- features: ['type-safe', 'validated', 'declarative', 'runtime-reload']
109
- }
110
- }
111
- })
97
+ // 4. Live Components (WebSocket support)
98
+ app.use(liveComponentsPlugin)
112
99
 
113
- // Registrar rotas da aplicação DEPOIS da rota de teste
114
- app.routes(apiRoutes)
100
+ // ===== Register Routes =====
101
+ // Note: Routes are now registered in app.ts (including envTestRoute)
102
+ app.routes(appInstance)
115
103
 
116
- // Swagger por último para descobrir todas as rotas
104
+ // ===== Final Setup =====
105
+
106
+ // Swagger documentation (must be last to discover all routes)
117
107
  app.use(swaggerPlugin)
118
108
 
119
- // Iniciar servidor (banner displayed by framework)
109
+ // ===== Start Server =====
110
+ // Banner will be displayed automatically by the framework
120
111
  app.listen()
121
112
 
122
-
123
-
124
- // Exportar tipo da aplicação para Eden Treaty (método correto)
113
+ // ===== Eden Treaty Type Export =====
114
+ // Export application type for type-safe client communication
125
115
  export type App = typeof app
@@ -1,8 +1,19 @@
1
- // 🧪 Manual Registration REMOVED for Auto-Generation Testing
2
- // This file is intentionally left empty to test the auto-generation system
3
- // The build system should automatically generate all imports and registrations
1
+ // ⚠️ DEPRECATION NOTICE
2
+ // This file has been moved to: core/server/live/auto-generated-components.ts
3
+ //
4
+ // The auto-generated component registration is now located in the core/ directory
5
+ // to prevent accidental user modifications and keep framework code separate from
6
+ // application code.
7
+ //
8
+ // If you're looking for component registration logic:
9
+ // - Generated file: core/server/live/auto-generated-components.ts (auto-generated during build)
10
+ // - Generator: core/build/live-components-generator.ts
11
+ // - Import location: app/server/index.ts
12
+ //
13
+ // To add new Live Components:
14
+ // 1. Create your component class in this directory (app/server/live/)
15
+ // 2. Extend LiveComponent class
16
+ // 3. Run 'bun run build' to regenerate the registration file
4
17
 
5
- // NOTE: If you see this in production, auto-generation worked!
6
- // All Live Components should be discovered and registered automatically during build
7
-
8
- // Removed startup log to keep output clean - auto-generation handles everything
18
+ // This file intentionally left empty - do not import
19
+ export {}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * 🔧 Environment Test Route
3
+ * Displays current configuration for debugging purposes
4
+ */
5
+
6
+ import { Elysia, t } from 'elysia'
7
+ import { appConfig } from '@/config/app.config'
8
+ import { serverConfig } from '@/config/server.config'
9
+ import { loggerConfig } from '@/config/logger.config'
10
+ import { appRuntimeConfig } from '@/config/runtime.config'
11
+ import { helpers } from '@/core/utils/env'
12
+
13
+ // Response schema for environment test
14
+ const EnvTestResponseSchema = t.Object({
15
+ message: t.String(),
16
+ timestamp: t.String(),
17
+ serverConfig: t.Object({
18
+ port: t.Number(),
19
+ host: t.String(),
20
+ apiPrefix: t.String(),
21
+ appName: t.String(),
22
+ appVersion: t.String(),
23
+ cors: t.Object({
24
+ origins: t.Array(t.String()),
25
+ methods: t.Array(t.String()),
26
+ credentials: t.Boolean()
27
+ }),
28
+ client: t.Object({
29
+ port: t.Number(),
30
+ target: t.String(),
31
+ sourceMaps: t.Boolean()
32
+ }),
33
+ features: t.Object({
34
+ enableSwagger: t.Boolean(),
35
+ enableMetrics: t.Boolean(),
36
+ enableMonitoring: t.Boolean()
37
+ })
38
+ }),
39
+ environment: t.Object({
40
+ NODE_ENV: t.String(),
41
+ DEBUG: t.Boolean(),
42
+ LOG_LEVEL: t.String()
43
+ }),
44
+ urls: t.Object({
45
+ server: t.String(),
46
+ client: t.String(),
47
+ swagger: t.String()
48
+ }),
49
+ system: t.Object({
50
+ version: t.String(),
51
+ features: t.Array(t.String())
52
+ })
53
+ }, {
54
+ description: 'Environment and configuration information for debugging'
55
+ })
56
+
57
+ /**
58
+ * Environment test endpoint
59
+ * Shows declarative config system information
60
+ */
61
+ export const envTestRoute = new Elysia({ prefix: '/api', tags: ['Development'] })
62
+ .get('/env-test', () => {
63
+ return {
64
+ message: '⚡ Declarative Config System!',
65
+ timestamp: new Date().toISOString(),
66
+ serverConfig: {
67
+ port: serverConfig.server.port,
68
+ host: serverConfig.server.host,
69
+ apiPrefix: serverConfig.server.apiPrefix,
70
+ appName: appConfig.name,
71
+ appVersion: appConfig.version,
72
+ cors: {
73
+ origins: serverConfig.cors.origins,
74
+ methods: serverConfig.cors.methods,
75
+ credentials: serverConfig.cors.credentials
76
+ },
77
+ client: {
78
+ port: serverConfig.server.backendPort,
79
+ target: 'es2020',
80
+ sourceMaps: false
81
+ },
82
+ features: {
83
+ enableSwagger: appRuntimeConfig.values.enableSwagger,
84
+ enableMetrics: appRuntimeConfig.values.enableMetrics,
85
+ enableMonitoring: appRuntimeConfig.values.enableMonitoring
86
+ }
87
+ },
88
+ environment: {
89
+ NODE_ENV: appConfig.env,
90
+ DEBUG: appRuntimeConfig.values.enableDebugMode,
91
+ LOG_LEVEL: loggerConfig.level
92
+ },
93
+ urls: {
94
+ server: helpers.getServerUrl(),
95
+ client: helpers.getClientUrl(),
96
+ swagger: `${helpers.getServerUrl()}/swagger`
97
+ },
98
+ system: {
99
+ version: 'declarative-config',
100
+ features: ['type-safe', 'validated', 'declarative', 'runtime-reload']
101
+ }
102
+ }
103
+ }, {
104
+ detail: {
105
+ summary: 'Environment Configuration Test',
106
+ description: 'Returns current environment configuration, server settings, and runtime features for debugging and validation',
107
+ tags: ['Development', 'Configuration', 'Debug']
108
+ },
109
+ response: EnvTestResponseSchema
110
+ })
@@ -1,9 +1,5 @@
1
1
  import { Elysia, t } from "elysia"
2
2
  import { usersRoutes } from "./users.routes"
3
- import { uploadRoutes } from "./upload"
4
- import { configRoutes } from "./config"
5
- import { cryptoAuthDemoRoutes } from "./crypto-auth-demo.routes"
6
- import { exemploPostsRoutes } from "./exemplo-posts.routes"
7
3
 
8
4
  export const apiRoutes = new Elysia({ prefix: "/api" })
9
5
  .get("/", () => ({ message: "🔥 Hot Reload funcionando! FluxStack API v1.4.0 ⚡" }), {
@@ -36,8 +32,5 @@ export const apiRoutes = new Elysia({ prefix: "/api" })
36
32
  description: 'Returns the current health status of the API server'
37
33
  }
38
34
  })
35
+ // Register users routes
39
36
  .use(usersRoutes)
40
- .use(uploadRoutes)
41
- .use(configRoutes)
42
- .use(cryptoAuthDemoRoutes)
43
- .use(exemploPostsRoutes) // ✅ Exemplo de rotas com crypto-auth
@@ -1,114 +1,215 @@
1
- import { Elysia, t } from "elysia"
2
- import { UsersController } from "../controllers/users.controller"
3
-
4
- export const usersRoutes = new Elysia({ prefix: "/users" })
5
- .get("/", () => UsersController.getUsers(), {
6
- response: t.Object({
7
- users: t.Array(t.Object({
8
- id: t.Number(),
9
- name: t.String(),
10
- email: t.String(),
11
- createdAt: t.Date()
12
- }))
13
- }),
1
+ import { Elysia, t } from 'elysia'
2
+ import { UsersController } from '@/app/server/controllers/users.controller'
3
+
4
+ // ===== Request/Response Schemas =====
5
+
6
+ const UserSchema = t.Object({
7
+ id: t.Number(),
8
+ name: t.String(),
9
+ email: t.String()
10
+ }, {
11
+ description: 'User object'
12
+ })
13
+
14
+ const CreateUserRequestSchema = t.Object({
15
+ name: t.String({ minLength: 2, description: 'User name (minimum 2 characters)' }),
16
+ email: t.String({ format: 'email', description: 'Valid email address' })
17
+ }, {
18
+ description: 'Request body for creating a new user'
19
+ })
20
+
21
+ const CreateUserResponseSchema = t.Union([
22
+ t.Object({
23
+ success: t.Literal(true),
24
+ user: UserSchema,
25
+ message: t.Optional(t.String())
26
+ }),
27
+ t.Object({
28
+ success: t.Literal(false),
29
+ error: t.String()
30
+ })
31
+ ], {
32
+ description: 'Response after attempting to create a user'
33
+ })
34
+
35
+ const GetUsersResponseSchema = t.Object({
36
+ success: t.Boolean(),
37
+ users: t.Array(UserSchema),
38
+ count: t.Number()
39
+ }, {
40
+ description: 'List of all users'
41
+ })
42
+
43
+ const GetUserResponseSchema = t.Union([
44
+ t.Object({
45
+ success: t.Literal(true),
46
+ user: UserSchema
47
+ }),
48
+ t.Object({
49
+ success: t.Literal(false),
50
+ error: t.String()
51
+ })
52
+ ], {
53
+ description: 'Single user or error'
54
+ })
55
+
56
+ const DeleteUserResponseSchema = t.Union([
57
+ t.Object({
58
+ success: t.Literal(true),
59
+ message: t.String()
60
+ }),
61
+ t.Object({
62
+ success: t.Literal(false),
63
+ message: t.String()
64
+ })
65
+ ], {
66
+ description: 'Result of delete operation'
67
+ })
68
+
69
+ const ErrorResponseSchema = t.Object({
70
+ error: t.String()
71
+ }, {
72
+ description: 'Error response'
73
+ })
74
+
75
+ /**
76
+ * Users API Routes
77
+ */
78
+ export const usersRoutes = new Elysia({ prefix: '/users', tags: ['Users'] })
79
+ // GET /users - Get all users
80
+ .get('/', async () => {
81
+ return await UsersController.getUsers()
82
+ }, {
14
83
  detail: {
15
- tags: ['Users'],
16
- summary: 'List Users',
17
- description: 'Retrieve a list of all users in the system'
18
- }
84
+ summary: 'Get All Users',
85
+ description: 'Retrieves a list of all registered users',
86
+ tags: ['Users', 'CRUD']
87
+ },
88
+ response: GetUsersResponseSchema
19
89
  })
20
-
21
- .get("/:id", async ({ params: { id }, set }) => {
22
- const userId = parseInt(id)
23
- const result = await UsersController.getUserById(userId)
24
-
90
+
91
+ // GET /users/:id - Get user by ID
92
+ .get('/:id', async ({ params, set }) => {
93
+ const id = parseInt(params.id)
94
+
95
+ // Handle invalid ID
96
+ if (isNaN(id)) {
97
+ set.status = 400
98
+ return { error: 'ID inválido' }
99
+ }
100
+
101
+ const result = await UsersController.getUserById(id)
102
+
25
103
  if (!result) {
26
104
  set.status = 404
27
- return { error: "Usuário não encontrado" }
105
+ return { error: 'Usuário não encontrado' }
28
106
  }
29
-
107
+
30
108
  return result
31
109
  }, {
32
- params: t.Object({
33
- id: t.String()
34
- }),
35
110
  detail: {
36
- tags: ['Users'],
37
111
  summary: 'Get User by ID',
38
- description: 'Retrieve a specific user by their ID'
112
+ description: 'Retrieves a single user by their unique identifier',
113
+ tags: ['Users', 'CRUD']
114
+ },
115
+ params: t.Object({
116
+ id: t.String({ description: 'User ID' })
117
+ }),
118
+ response: {
119
+ 200: GetUserResponseSchema,
120
+ 400: ErrorResponseSchema,
121
+ 404: ErrorResponseSchema
39
122
  }
40
123
  })
41
-
42
- .post("/", async ({ body, set }) => {
43
- try {
44
- return await UsersController.createUser(body as any)
45
- } catch (error) {
124
+
125
+ // POST /users - Create new user
126
+ .post('/', async ({ body, set }) => {
127
+ // Validate required fields
128
+ if (!body.name || !body.email) {
129
+ set.status = 400
130
+ return {
131
+ success: false,
132
+ error: 'Nome e email são obrigatórios'
133
+ }
134
+ }
135
+
136
+ // Validate name length
137
+ if (body.name.length < 2) {
138
+ set.status = 400
139
+ return {
140
+ success: false,
141
+ error: 'Nome deve ter pelo menos 2 caracteres'
142
+ }
143
+ }
144
+
145
+ // Validate email format
146
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
147
+ if (!emailRegex.test(body.email)) {
46
148
  set.status = 400
47
- return {
48
- success: false,
49
- error: "Dados inválidos",
50
- details: error instanceof Error ? error.message : 'Unknown error'
149
+ return {
150
+ success: false,
151
+ error: 'Email inválido'
51
152
  }
52
153
  }
154
+
155
+ const result = await UsersController.createUser(body)
156
+
157
+ // If email is duplicate, still return 200 but with success: false
158
+ if (!result.success) {
159
+ return result
160
+ }
161
+
162
+ return result
53
163
  }, {
54
- body: t.Object({
55
- name: t.String({ minLength: 2 }),
56
- email: t.String({ format: "email" })
57
- }),
58
- response: t.Object({
59
- success: t.Boolean(),
60
- user: t.Optional(t.Object({
61
- id: t.Number(),
62
- name: t.String(),
63
- email: t.String(),
64
- createdAt: t.Date()
65
- })),
66
- message: t.Optional(t.String())
67
- }),
68
164
  detail: {
69
- tags: ['Users'],
70
- summary: 'Create User',
71
- description: 'Create a new user with name and email'
165
+ summary: 'Create New User',
166
+ description: 'Creates a new user with name and email. Email must be unique.',
167
+ tags: ['Users', 'CRUD']
72
168
  },
73
- error({ code, error, set }) {
74
- switch (code) {
75
- case 'VALIDATION':
76
- set.status = 400
77
- return {
78
- success: false,
79
- error: "Dados inválidos",
80
- details: error.message
81
- }
82
- default:
83
- set.status = 500
84
- return {
85
- success: false,
86
- error: "Erro interno do servidor"
87
- }
88
- }
169
+ body: CreateUserRequestSchema,
170
+ response: {
171
+ 200: CreateUserResponseSchema,
172
+ 400: t.Object({
173
+ success: t.Literal(false),
174
+ error: t.String()
175
+ })
89
176
  }
90
177
  })
91
-
92
- .delete("/:id", ({ params: { id } }) => {
93
- const userId = parseInt(id)
94
- return UsersController.deleteUser(userId)
178
+
179
+ // DELETE /users/:id - Delete user
180
+ .delete('/:id', async ({ params, set }) => {
181
+ const id = parseInt(params.id)
182
+
183
+ if (isNaN(id)) {
184
+ set.status = 400
185
+ return {
186
+ success: false,
187
+ message: 'ID inválido'
188
+ }
189
+ }
190
+
191
+ const result = await UsersController.deleteUser(id)
192
+
193
+ if (!result.success) {
194
+ // Don't set 404 status, just return success: false
195
+ return result
196
+ }
197
+
198
+ return result
95
199
  }, {
96
- params: t.Object({
97
- id: t.String()
98
- }),
99
- response: t.Object({
100
- success: t.Boolean(),
101
- user: t.Optional(t.Object({
102
- id: t.Number(),
103
- name: t.String(),
104
- email: t.String(),
105
- createdAt: t.Date()
106
- })),
107
- message: t.Optional(t.String())
108
- }),
109
200
  detail: {
110
- tags: ['Users'],
111
201
  summary: 'Delete User',
112
- description: 'Delete a user by their ID'
202
+ description: 'Deletes a user by their ID',
203
+ tags: ['Users', 'CRUD']
204
+ },
205
+ params: t.Object({
206
+ id: t.String({ description: 'User ID to delete' })
207
+ }),
208
+ response: {
209
+ 200: DeleteUserResponseSchema,
210
+ 400: t.Object({
211
+ success: t.Literal(false),
212
+ message: t.String()
213
+ })
113
214
  }
114
- })
215
+ })