create-fluxstack 1.8.1 → 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.
- package/.env.example +19 -0
- package/README.md +6 -3
- package/app/client/SIMPLIFICATION.md +140 -0
- package/app/client/frontend-only.ts +1 -1
- package/app/client/src/App.tsx +148 -283
- package/app/client/src/index.css +5 -20
- package/app/client/src/lib/eden-api.ts +53 -220
- package/app/client/src/main.tsx +2 -3
- package/app/server/controllers/users.controller.ts +57 -31
- package/app/server/index.ts +5 -2
- package/app/server/live/register-components.ts +18 -7
- package/app/server/routes/env-test.ts +53 -2
- package/app/server/routes/index.ts +1 -8
- package/app/server/routes/users.routes.ts +192 -91
- package/config/fluxstack.config.ts +2 -2
- package/config/plugins.config.ts +22 -1
- package/core/build/flux-plugins-generator.ts +5 -5
- package/core/build/live-components-generator.ts +15 -12
- package/core/cli/command-registry.ts +4 -14
- package/core/cli/commands/plugin-deps.ts +8 -8
- package/core/cli/generators/component.ts +3 -3
- package/core/cli/generators/controller.ts +4 -4
- package/core/cli/generators/index.ts +8 -8
- package/core/cli/generators/interactive.ts +4 -4
- package/core/cli/generators/plugin.ts +3 -3
- package/core/cli/generators/prompts.ts +1 -1
- package/core/cli/generators/route.ts +27 -11
- package/core/cli/generators/service.ts +5 -5
- package/core/cli/generators/template-engine.ts +1 -1
- package/core/cli/generators/types.ts +1 -1
- package/core/cli/index.ts +158 -193
- package/core/cli/plugin-discovery.ts +3 -3
- package/core/client/hooks/index.ts +2 -2
- package/core/client/hooks/state-validator.ts +1 -1
- package/core/client/hooks/useAuth.ts +1 -1
- package/core/client/hooks/useChunkedUpload.ts +1 -1
- package/core/client/hooks/useHybridLiveComponent.ts +1 -1
- package/core/client/hooks/useWebSocket.ts +1 -1
- package/core/config/env.ts +1 -1
- package/core/config/runtime-config.ts +5 -5
- package/core/config/schema.ts +9 -0
- package/core/framework/server.ts +30 -15
- package/core/framework/types.ts +2 -2
- package/core/live/ComponentRegistry.ts +1 -1
- package/core/plugins/built-in/live-components/commands/create-live-component.ts +1 -1
- package/core/plugins/built-in/live-components/index.ts +1 -1
- package/core/plugins/built-in/monitoring/index.ts +65 -161
- package/core/plugins/built-in/static/index.ts +18 -47
- package/core/plugins/built-in/swagger/index.ts +301 -231
- package/core/plugins/built-in/vite/index.ts +74 -109
- package/core/plugins/config.ts +2 -2
- package/core/plugins/dependency-manager.ts +2 -2
- package/core/plugins/discovery.ts +1 -1
- package/core/plugins/executor.ts +2 -2
- package/core/plugins/manager.ts +19 -4
- package/core/plugins/module-resolver.ts +1 -1
- package/core/plugins/registry.ts +3 -3
- package/core/plugins/types.ts +147 -5
- package/core/server/framework.ts +2 -2
- package/core/server/live/ComponentRegistry.ts +9 -26
- package/core/server/live/FileUploadManager.ts +1 -1
- package/core/server/live/auto-generated-components.ts +26 -0
- package/core/server/live/websocket-plugin.ts +211 -19
- package/core/server/middleware/errorHandling.ts +1 -1
- package/core/server/middleware/index.ts +4 -4
- package/core/server/plugins/database.ts +1 -2
- package/core/server/plugins/static-files-plugin.ts +259 -231
- package/core/server/plugins/swagger.ts +1 -1
- package/core/server/services/BaseService.ts +1 -1
- package/core/server/services/ServiceContainer.ts +1 -1
- package/core/server/services/index.ts +4 -4
- package/core/server/standalone.ts +16 -1
- package/core/testing/index.ts +1 -1
- package/core/testing/setup.ts +1 -1
- package/core/utils/logger/startup-banner.ts +7 -33
- package/core/utils/version.ts +6 -6
- package/create-fluxstack.ts +68 -25
- package/package.json +2 -2
- package/plugins/crypto-auth/index.ts +52 -47
- package/plugins/crypto-auth/server/AuthMiddleware.ts +1 -1
- package/plugins/crypto-auth/server/middlewares/helpers.ts +16 -1
- package/vitest.config.ts +11 -2
- package/app/client/src/App.css +0 -883
- package/app/client/src/components/ErrorBoundary.tsx +0 -107
- package/app/client/src/components/ErrorDisplay.css +0 -365
- package/app/client/src/components/ErrorDisplay.tsx +0 -258
- package/app/client/src/components/FluxStackConfig.tsx +0 -1321
- package/app/client/src/components/HybridLiveCounter.tsx +0 -140
- package/app/client/src/components/LiveClock.tsx +0 -286
- package/app/client/src/components/MainLayout.tsx +0 -388
- package/app/client/src/components/SidebarNavigation.tsx +0 -391
- package/app/client/src/components/StateDemo.tsx +0 -178
- package/app/client/src/components/SystemMonitor.tsx +0 -1044
- package/app/client/src/components/UserProfile.tsx +0 -809
- package/app/client/src/hooks/useAuth.ts +0 -39
- package/app/client/src/hooks/useNotifications.ts +0 -56
- package/app/client/src/lib/errors.ts +0 -340
- package/app/client/src/lib/hooks/useErrorHandler.ts +0 -258
- package/app/client/src/lib/index.ts +0 -45
- package/app/client/src/pages/ApiDocs.tsx +0 -182
- package/app/client/src/pages/CryptoAuthPage.tsx +0 -394
- package/app/client/src/pages/Demo.tsx +0 -174
- package/app/client/src/pages/HybridLive.tsx +0 -263
- package/app/client/src/pages/Overview.tsx +0 -155
- package/app/client/src/store/README.md +0 -43
- package/app/client/src/store/index.ts +0 -16
- package/app/client/src/store/slices/uiSlice.ts +0 -151
- package/app/client/src/store/slices/userSlice.ts +0 -161
- package/app/client/src/test/README.md +0 -257
- package/app/client/src/test/setup.ts +0 -70
- package/app/client/src/test/types.ts +0 -12
- package/app/server/live/CounterComponent.ts +0 -191
- package/app/server/live/FluxStackConfig.ts +0 -534
- package/app/server/live/SidebarNavigation.ts +0 -157
- package/app/server/live/SystemMonitor.ts +0 -595
- package/app/server/live/SystemMonitorIntegration.ts +0 -151
- package/app/server/live/UserProfileComponent.ts +0 -141
- package/app/server/middleware/auth.ts +0 -136
- package/app/server/middleware/errorHandling.ts +0 -252
- package/app/server/middleware/index.ts +0 -10
- package/app/server/middleware/rateLimit.ts +0 -193
- package/app/server/middleware/requestLogging.ts +0 -215
- package/app/server/middleware/validation.ts +0 -270
- package/app/server/routes/config.ts +0 -145
- package/app/server/routes/crypto-auth-demo.routes.ts +0 -167
- package/app/server/routes/example-with-crypto-auth.routes.ts +0 -235
- package/app/server/routes/exemplo-posts.routes.ts +0 -161
- package/app/server/routes/upload.ts +0 -92
- package/app/server/services/NotificationService.ts +0 -302
- package/app/server/services/UserService.ts +0 -222
- package/app/server/services/index.ts +0 -46
- package/app/server/types/index.ts +0 -1
|
@@ -1,114 +1,215 @@
|
|
|
1
|
-
import { Elysia, t } from
|
|
2
|
-
import { UsersController } from
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
const
|
|
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:
|
|
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: '
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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:
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
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
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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: '
|
|
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
|
+
})
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* @deprecated Use the configuration from the root fluxstack.config.ts instead
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { getConfigSync, createLegacyConfig } from '
|
|
8
|
-
import type { FluxStackConfig } from '
|
|
7
|
+
import { getConfigSync, createLegacyConfig } from '@/core/config'
|
|
8
|
+
import type { FluxStackConfig } from '@/core/config'
|
|
9
9
|
|
|
10
10
|
// Load the new configuration
|
|
11
11
|
const newConfig = getConfigSync()
|
package/config/plugins.config.ts
CHANGED
|
@@ -28,7 +28,8 @@ const pluginsConfigSchema = {
|
|
|
28
28
|
// Logger plugin (handled by logger.config.ts)
|
|
29
29
|
loggerEnabled: config.boolean('LOGGER_PLUGIN_ENABLED', true),
|
|
30
30
|
|
|
31
|
-
// Swagger plugin
|
|
31
|
+
// Swagger plugin
|
|
32
|
+
swaggerEnabled: config.boolean('SWAGGER_ENABLED', true),
|
|
32
33
|
swaggerTitle: config.string('SWAGGER_TITLE', 'FluxStack API'),
|
|
33
34
|
swaggerVersion: config.string('SWAGGER_VERSION', FLUXSTACK_VERSION),
|
|
34
35
|
swaggerDescription: config.string(
|
|
@@ -37,6 +38,26 @@ const pluginsConfigSchema = {
|
|
|
37
38
|
),
|
|
38
39
|
swaggerPath: config.string('SWAGGER_PATH', '/swagger'),
|
|
39
40
|
|
|
41
|
+
// Swagger advanced options
|
|
42
|
+
swaggerExcludePaths: config.array('SWAGGER_EXCLUDE_PATHS', []),
|
|
43
|
+
|
|
44
|
+
// Swagger servers (comma-separated list of URLs)
|
|
45
|
+
// Format: "url1|description1,url2|description2"
|
|
46
|
+
// Example: "https://api.prod.com|Production,https://api.staging.com|Staging"
|
|
47
|
+
swaggerServers: config.string('SWAGGER_SERVERS', ''),
|
|
48
|
+
|
|
49
|
+
// Swagger UI options
|
|
50
|
+
swaggerPersistAuthorization: config.boolean('SWAGGER_PERSIST_AUTH', true),
|
|
51
|
+
swaggerDisplayRequestDuration: config.boolean('SWAGGER_DISPLAY_DURATION', true),
|
|
52
|
+
swaggerEnableFilter: config.boolean('SWAGGER_ENABLE_FILTER', true),
|
|
53
|
+
swaggerShowExtensions: config.boolean('SWAGGER_SHOW_EXTENSIONS', true),
|
|
54
|
+
swaggerTryItOutEnabled: config.boolean('SWAGGER_TRY_IT_OUT', true),
|
|
55
|
+
|
|
56
|
+
// Swagger authentication (Basic Auth)
|
|
57
|
+
swaggerAuthEnabled: config.boolean('SWAGGER_AUTH_ENABLED', false),
|
|
58
|
+
swaggerAuthUsername: config.string('SWAGGER_AUTH_USERNAME', 'admin'),
|
|
59
|
+
swaggerAuthPassword: config.string('SWAGGER_AUTH_PASSWORD', ''),
|
|
60
|
+
|
|
40
61
|
// Static files plugin
|
|
41
62
|
staticFilesEnabled: config.boolean('STATIC_FILES_ENABLED', true),
|
|
42
63
|
staticPublicDir: config.string('STATIC_PUBLIC_DIR', 'public'),
|
|
@@ -95,12 +95,12 @@ export class FluxPluginsGenerator {
|
|
|
95
95
|
private findPluginEntryFile(pluginDir: string): string | null {
|
|
96
96
|
const possibleFiles = [
|
|
97
97
|
'index.ts',
|
|
98
|
-
'index
|
|
98
|
+
'index',
|
|
99
99
|
'plugin.ts',
|
|
100
|
-
'plugin
|
|
100
|
+
'plugin',
|
|
101
101
|
'src/index.ts',
|
|
102
|
-
'src/index
|
|
103
|
-
'dist/index
|
|
102
|
+
'src/index',
|
|
103
|
+
'dist/index'
|
|
104
104
|
]
|
|
105
105
|
|
|
106
106
|
for (const file of possibleFiles) {
|
|
@@ -130,7 +130,7 @@ export class FluxPluginsGenerator {
|
|
|
130
130
|
const imports = plugins
|
|
131
131
|
.map(plugin => {
|
|
132
132
|
const importName = this.getImportName(plugin.pluginName)
|
|
133
|
-
const importPath = plugin.entryFile === 'index.ts' || plugin.entryFile === 'index
|
|
133
|
+
const importPath = plugin.entryFile === 'index.ts' || plugin.entryFile === 'index'
|
|
134
134
|
? plugin.relativePath
|
|
135
135
|
: `${plugin.relativePath}/${plugin.entryFile.replace(/\.(ts|js)$/, '')}`
|
|
136
136
|
return `import ${importName} from "${importPath}"`
|
|
@@ -18,9 +18,12 @@ export class LiveComponentsGenerator {
|
|
|
18
18
|
private backupFilePath: string
|
|
19
19
|
|
|
20
20
|
constructor() {
|
|
21
|
+
// Scan components from app/ directory (user code)
|
|
21
22
|
this.componentsPath = join(process.cwd(), 'app', 'server', 'live')
|
|
22
|
-
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
// Generate registration file in core/ directory (framework code - protected from user modifications)
|
|
25
|
+
this.registrationFilePath = join(process.cwd(), 'core', 'server', 'live', 'auto-generated-components.ts')
|
|
26
|
+
this.backupFilePath = join(process.cwd(), 'core', 'server', 'live', 'auto-generated-components.backup.ts')
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
/**
|
|
@@ -64,7 +67,8 @@ export class LiveComponentsGenerator {
|
|
|
64
67
|
fileName,
|
|
65
68
|
className,
|
|
66
69
|
componentName,
|
|
67
|
-
|
|
70
|
+
// Path relative to core/server/live/ where the generated file will be
|
|
71
|
+
filePath: `@/app/server/live/${fileName}`
|
|
68
72
|
})
|
|
69
73
|
|
|
70
74
|
buildLogger.step(`Discovered component: ${className} → ${componentName}`)
|
|
@@ -190,18 +194,17 @@ ${components.map(comp => ` ${comp.className}`).join(',\n')}
|
|
|
190
194
|
}
|
|
191
195
|
|
|
192
196
|
/**
|
|
193
|
-
* Post-build hook: Clean up
|
|
197
|
+
* Post-build hook: Clean up backup file
|
|
198
|
+
* Note: Since the generated file is now in core/, we always keep it (it's bundled into production)
|
|
194
199
|
*/
|
|
195
|
-
async postBuild(keepGenerated: boolean =
|
|
200
|
+
async postBuild(keepGenerated: boolean = true): Promise<void> {
|
|
196
201
|
buildLogger.step('Cleaning up Live Components registration...')
|
|
197
202
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
} else {
|
|
204
|
-
this.restoreOriginalFile()
|
|
203
|
+
// Always keep the generated file in core/ (it gets bundled)
|
|
204
|
+
// Just remove the backup
|
|
205
|
+
if (existsSync(this.backupFilePath)) {
|
|
206
|
+
unlinkSync(this.backupFilePath)
|
|
207
|
+
buildLogger.step('Removed backup file')
|
|
205
208
|
}
|
|
206
209
|
}
|
|
207
210
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CliCommand, CliContext, CliArgument, CliOption } from "../plugins/types"
|
|
2
|
-
import { getConfigSync } from "
|
|
3
|
-
import { logger } from "
|
|
2
|
+
import { getConfigSync } from "@/core/config"
|
|
3
|
+
import { logger } from "@/core/utils/logger"
|
|
4
4
|
import { createTimer, formatBytes, isProduction, isDevelopment } from "../utils/helpers"
|
|
5
5
|
|
|
6
6
|
export class CliCommandRegistry {
|
|
@@ -10,20 +10,10 @@ export class CliCommandRegistry {
|
|
|
10
10
|
|
|
11
11
|
constructor() {
|
|
12
12
|
const config = getConfigSync()
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
this.context = {
|
|
15
15
|
config,
|
|
16
|
-
logger:
|
|
17
|
-
debug: (message: string, meta?: unknown) => logger.debug(message, meta),
|
|
18
|
-
info: (message: string, meta?: unknown) => logger.info(message, meta),
|
|
19
|
-
warn: (message: string, meta?: unknown) => logger.warn(message, meta),
|
|
20
|
-
error: (message: string, meta?: unknown) => logger.error(message, meta),
|
|
21
|
-
child: (context: Record<string, unknown>) => logger,
|
|
22
|
-
time: (label: string) => logger.time(label),
|
|
23
|
-
timeEnd: (label: string) => logger.timeEnd(label),
|
|
24
|
-
request: (method: string, path: string, status?: number, duration?: number) =>
|
|
25
|
-
logger.request(method, path, status, duration)
|
|
26
|
-
},
|
|
16
|
+
logger: logger as any,
|
|
27
17
|
utils: {
|
|
28
18
|
createTimer,
|
|
29
19
|
formatBytes,
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import { Command } from 'commander'
|
|
6
6
|
import chalk from 'chalk'
|
|
7
|
-
import { PluginDependencyManager } from '
|
|
8
|
-
import { PluginRegistry } from '
|
|
7
|
+
import { PluginDependencyManager } from '@/core/plugins/dependency-manager'
|
|
8
|
+
import { PluginRegistry } from '@/core/plugins/registry'
|
|
9
9
|
import { existsSync, readFileSync } from 'fs'
|
|
10
10
|
import { join } from 'path'
|
|
11
11
|
|
|
@@ -32,11 +32,11 @@ function createInstallCommand(): Command {
|
|
|
32
32
|
const dependencyManager = new PluginDependencyManager({
|
|
33
33
|
autoInstall: !options.dryRun,
|
|
34
34
|
packageManager: options.packageManager,
|
|
35
|
-
logger: createConsoleLogger()
|
|
35
|
+
logger: createConsoleLogger() as any as any
|
|
36
36
|
})
|
|
37
37
|
|
|
38
38
|
const registry = new PluginRegistry({
|
|
39
|
-
logger: createConsoleLogger()
|
|
39
|
+
logger: createConsoleLogger() as any as any
|
|
40
40
|
})
|
|
41
41
|
|
|
42
42
|
// Descobrir plugins
|
|
@@ -104,7 +104,7 @@ function createListCommand(): Command {
|
|
|
104
104
|
|
|
105
105
|
try {
|
|
106
106
|
const registry = new PluginRegistry({
|
|
107
|
-
logger: createConsoleLogger()
|
|
107
|
+
logger: createConsoleLogger() as any
|
|
108
108
|
})
|
|
109
109
|
|
|
110
110
|
const results = await registry.discoverPlugins({
|
|
@@ -113,7 +113,7 @@ function createListCommand(): Command {
|
|
|
113
113
|
|
|
114
114
|
const dependencyManager = new PluginDependencyManager({
|
|
115
115
|
autoInstall: false,
|
|
116
|
-
logger: createConsoleLogger()
|
|
116
|
+
logger: createConsoleLogger() as any
|
|
117
117
|
})
|
|
118
118
|
|
|
119
119
|
for (const result of results) {
|
|
@@ -162,7 +162,7 @@ function createCheckCommand(): Command {
|
|
|
162
162
|
|
|
163
163
|
try {
|
|
164
164
|
const registry = new PluginRegistry({
|
|
165
|
-
logger: createConsoleLogger()
|
|
165
|
+
logger: createConsoleLogger() as any
|
|
166
166
|
})
|
|
167
167
|
|
|
168
168
|
const results = await registry.discoverPlugins({
|
|
@@ -171,7 +171,7 @@ function createCheckCommand(): Command {
|
|
|
171
171
|
|
|
172
172
|
const dependencyManager = new PluginDependencyManager({
|
|
173
173
|
autoInstall: false,
|
|
174
|
-
logger: createConsoleLogger()
|
|
174
|
+
logger: createConsoleLogger() as any
|
|
175
175
|
})
|
|
176
176
|
|
|
177
177
|
const resolutions = []
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Generator } from "./index
|
|
2
|
-
import type { GeneratorContext, GeneratorOptions, Template } from "./types
|
|
3
|
-
import { templateEngine } from "./template-engine
|
|
1
|
+
import type { Generator } from "./index"
|
|
2
|
+
import type { GeneratorContext, GeneratorOptions, Template } from "./types"
|
|
3
|
+
import { templateEngine } from "./template-engine"
|
|
4
4
|
|
|
5
5
|
export class ComponentGenerator implements Generator {
|
|
6
6
|
name = 'component'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Generator } from "./index
|
|
2
|
-
import type { GeneratorContext, GeneratorOptions, Template } from "./types
|
|
3
|
-
import { templateEngine } from "./template-engine
|
|
1
|
+
import type { Generator } from "./index"
|
|
2
|
+
import type { GeneratorContext, GeneratorOptions, Template } from "./types"
|
|
3
|
+
import { templateEngine } from "./template-engine"
|
|
4
4
|
|
|
5
5
|
export class ControllerGenerator implements Generator {
|
|
6
6
|
name = 'controller'
|
|
@@ -55,7 +55,7 @@ export class ControllerGenerator implements Generator {
|
|
|
55
55
|
content: `import { Elysia, t } from 'elysia'
|
|
56
56
|
import { {{pascalName}}Service } from '../services/{{kebabName}}.service'
|
|
57
57
|
import { {{pascalName}}Schema, Create{{pascalName}}Schema, Update{{pascalName}}Schema } from '../schemas/{{kebabName}}.schema'
|
|
58
|
-
import { NotFoundError, ValidationError } from '
|
|
58
|
+
import { NotFoundError, ValidationError } from '@/core/utils/errors'
|
|
59
59
|
|
|
60
60
|
export class {{pascalName}}Controller {
|
|
61
61
|
private service: {{pascalName}}Service
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { CliCommand } from "../../plugins/types
|
|
2
|
-
import { ControllerGenerator } from "./controller
|
|
3
|
-
import { RouteGenerator } from "./route
|
|
4
|
-
import { ComponentGenerator } from "./component
|
|
5
|
-
import { ServiceGenerator } from "./service
|
|
6
|
-
import { PluginGenerator } from "./plugin
|
|
7
|
-
import type { GeneratorContext, GeneratorOptions } from "./types
|
|
1
|
+
import type { CliCommand } from "../../plugins/types"
|
|
2
|
+
import { ControllerGenerator } from "./controller"
|
|
3
|
+
import { RouteGenerator } from "./route"
|
|
4
|
+
import { ComponentGenerator } from "./component"
|
|
5
|
+
import { ServiceGenerator } from "./service"
|
|
6
|
+
import { PluginGenerator } from "./plugin"
|
|
7
|
+
import type { GeneratorContext, GeneratorOptions } from "./types"
|
|
8
8
|
|
|
9
9
|
export interface Generator {
|
|
10
10
|
name: string
|
|
@@ -47,7 +47,7 @@ export class GeneratorRegistry {
|
|
|
47
47
|
export const generatorRegistry = new GeneratorRegistry()
|
|
48
48
|
|
|
49
49
|
// Export additional commands
|
|
50
|
-
export { interactiveGenerateCommand } from "./interactive
|
|
50
|
+
export { interactiveGenerateCommand } from "./interactive"
|
|
51
51
|
|
|
52
52
|
// CLI command for code generation
|
|
53
53
|
export const generateCommand: CliCommand = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { CliCommand } from "../../plugins/types
|
|
2
|
-
import { generatorRegistry } from "./index
|
|
3
|
-
import type { GeneratorContext, GeneratorOptions } from "./types
|
|
4
|
-
import { promptSystem } from "./prompts
|
|
1
|
+
import type { CliCommand } from "../../plugins/types"
|
|
2
|
+
import { generatorRegistry } from "./index"
|
|
3
|
+
import type { GeneratorContext, GeneratorOptions } from "./types"
|
|
4
|
+
import { promptSystem } from "./prompts"
|
|
5
5
|
|
|
6
6
|
export const interactiveGenerateCommand: CliCommand = {
|
|
7
7
|
name: 'generate:interactive',
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Generator } from "./index
|
|
2
|
-
import type { GeneratorContext, GeneratorOptions, Template } from "./types
|
|
3
|
-
import { templateEngine } from "./template-engine
|
|
1
|
+
import type { Generator } from "./index"
|
|
2
|
+
import type { GeneratorContext, GeneratorOptions, Template } from "./types"
|
|
3
|
+
import { templateEngine } from "./template-engine"
|
|
4
4
|
import { join } from "path"
|
|
5
5
|
|
|
6
6
|
export class PluginGenerator implements Generator {
|