create-fluxstack 1.5.2 → 1.5.4

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 (52) hide show
  1. package/.env.example +8 -1
  2. package/CRYPTO-AUTH-MIDDLEWARE-GUIDE.md +475 -0
  3. package/CRYPTO-AUTH-MIDDLEWARES.md +473 -0
  4. package/CRYPTO-AUTH-USAGE.md +491 -0
  5. package/EXEMPLO-ROTA-PROTEGIDA.md +347 -0
  6. package/QUICK-START-CRYPTO-AUTH.md +221 -0
  7. package/app/client/src/App.tsx +4 -1
  8. package/app/client/src/pages/CryptoAuthPage.tsx +394 -0
  9. package/app/server/index.ts +4 -0
  10. package/app/server/live/FluxStackConfig.ts +1 -1
  11. package/app/server/routes/crypto-auth-demo.routes.ts +167 -0
  12. package/app/server/routes/example-with-crypto-auth.routes.ts +235 -0
  13. package/app/server/routes/exemplo-posts.routes.ts +161 -0
  14. package/app/server/routes/index.ts +5 -1
  15. package/config/index.ts +9 -1
  16. package/core/cli/generators/plugin.ts +324 -34
  17. package/core/cli/generators/template-engine.ts +5 -0
  18. package/core/cli/plugin-discovery.ts +33 -12
  19. package/core/framework/server.ts +10 -0
  20. package/core/plugins/dependency-manager.ts +89 -22
  21. package/core/plugins/index.ts +4 -0
  22. package/core/plugins/manager.ts +3 -2
  23. package/core/plugins/module-resolver.ts +216 -0
  24. package/core/plugins/registry.ts +28 -1
  25. package/core/templates/create-project.ts +7 -0
  26. package/core/utils/logger/index.ts +4 -0
  27. package/core/utils/version.ts +1 -1
  28. package/fluxstack.config.ts +253 -114
  29. package/package.json +3 -3
  30. package/plugins/crypto-auth/README.md +788 -0
  31. package/plugins/crypto-auth/ai-context.md +1282 -0
  32. package/plugins/crypto-auth/cli/make-protected-route.command.ts +383 -0
  33. package/plugins/crypto-auth/client/CryptoAuthClient.ts +302 -0
  34. package/plugins/crypto-auth/client/components/AuthProvider.tsx +131 -0
  35. package/plugins/crypto-auth/client/components/LoginButton.tsx +138 -0
  36. package/plugins/crypto-auth/client/components/ProtectedRoute.tsx +89 -0
  37. package/plugins/crypto-auth/client/components/index.ts +12 -0
  38. package/plugins/crypto-auth/client/index.ts +12 -0
  39. package/plugins/crypto-auth/config/index.ts +34 -0
  40. package/plugins/crypto-auth/index.ts +162 -0
  41. package/plugins/crypto-auth/package.json +66 -0
  42. package/plugins/crypto-auth/server/AuthMiddleware.ts +181 -0
  43. package/plugins/crypto-auth/server/CryptoAuthService.ts +186 -0
  44. package/plugins/crypto-auth/server/index.ts +22 -0
  45. package/plugins/crypto-auth/server/middlewares/cryptoAuthAdmin.ts +65 -0
  46. package/plugins/crypto-auth/server/middlewares/cryptoAuthOptional.ts +26 -0
  47. package/plugins/crypto-auth/server/middlewares/cryptoAuthPermissions.ts +76 -0
  48. package/plugins/crypto-auth/server/middlewares/cryptoAuthRequired.ts +45 -0
  49. package/plugins/crypto-auth/server/middlewares/helpers.ts +140 -0
  50. package/plugins/crypto-auth/server/middlewares/index.ts +22 -0
  51. package/plugins/crypto-auth/server/middlewares.ts +19 -0
  52. package/test-crypto-auth.ts +101 -0
@@ -0,0 +1,235 @@
1
+ /**
2
+ * Exemplo de uso dos middlewares crypto-auth
3
+ * Demonstra como proteger rotas com autenticação criptográfica
4
+ */
5
+
6
+ import { Elysia, t } from 'elysia'
7
+ import {
8
+ cryptoAuthRequired,
9
+ cryptoAuthAdmin,
10
+ cryptoAuthPermissions,
11
+ cryptoAuthOptional,
12
+ getCryptoAuthUser,
13
+ isCryptoAuthAdmin
14
+ } from '@/plugins/crypto-auth/server'
15
+
16
+ // ========================================
17
+ // 1️⃣ ROTAS QUE REQUEREM AUTENTICAÇÃO
18
+ // ========================================
19
+
20
+ export const protectedRoutes = new Elysia()
21
+ // ✅ Aplica middleware a TODAS as rotas deste grupo
22
+ .use(cryptoAuthRequired())
23
+
24
+ // Agora TODAS as rotas abaixo requerem autenticação
25
+ .get('/users/me', ({ request }) => {
26
+ const user = getCryptoAuthUser(request)!
27
+
28
+ return {
29
+ profile: {
30
+ publicKey: user.publicKey,
31
+ isAdmin: user.isAdmin,
32
+ permissions: user.permissions
33
+ }
34
+ }
35
+ })
36
+
37
+ .get('/users', ({ request }) => {
38
+ const user = getCryptoAuthUser(request)!
39
+
40
+ return {
41
+ users: [
42
+ { id: 1, name: 'João' },
43
+ { id: 2, name: 'Maria' }
44
+ ],
45
+ requestedBy: user.publicKey.substring(0, 16) + '...'
46
+ }
47
+ })
48
+
49
+ .post('/posts', ({ request, body }) => {
50
+ const user = getCryptoAuthUser(request)!
51
+ const { title, content } = body as { title: string; content: string }
52
+
53
+ return {
54
+ success: true,
55
+ post: {
56
+ title,
57
+ content,
58
+ author: user.publicKey,
59
+ createdAt: new Date()
60
+ }
61
+ }
62
+ }, {
63
+ body: t.Object({
64
+ title: t.String(),
65
+ content: t.String()
66
+ })
67
+ })
68
+
69
+ // ========================================
70
+ // 2️⃣ ROTAS QUE REQUEREM ADMIN
71
+ // ========================================
72
+
73
+ export const adminRoutes = new Elysia()
74
+ // ✅ Apenas admins podem acessar
75
+ .use(cryptoAuthAdmin())
76
+
77
+ .get('/admin/stats', () => ({
78
+ totalUsers: 100,
79
+ totalPosts: 500,
80
+ systemHealth: 'optimal'
81
+ }))
82
+
83
+ .delete('/admin/users/:id', ({ params, request }) => {
84
+ const user = getCryptoAuthUser(request)!
85
+
86
+ return {
87
+ success: true,
88
+ message: `Usuário ${params.id} deletado`,
89
+ deletedBy: user.publicKey
90
+ }
91
+ })
92
+
93
+ .post('/admin/broadcast', ({ body }) => ({
94
+ success: true,
95
+ message: 'Mensagem enviada para todos os usuários',
96
+ content: body
97
+ }), {
98
+ body: t.Object({
99
+ message: t.String()
100
+ })
101
+ })
102
+
103
+ // ========================================
104
+ // 3️⃣ ROTAS COM PERMISSÕES ESPECÍFICAS
105
+ // ========================================
106
+
107
+ export const writeRoutes = new Elysia()
108
+ // ✅ Requer permissão 'write'
109
+ .use(cryptoAuthPermissions(['write']))
110
+
111
+ .put('/posts/:id', ({ params, body }) => ({
112
+ success: true,
113
+ message: `Post ${params.id} atualizado`,
114
+ data: body
115
+ }), {
116
+ body: t.Object({
117
+ title: t.Optional(t.String()),
118
+ content: t.Optional(t.String())
119
+ })
120
+ })
121
+
122
+ .patch('/posts/:id/publish', ({ params }) => ({
123
+ success: true,
124
+ message: `Post ${params.id} publicado`
125
+ }))
126
+
127
+ // ========================================
128
+ // 4️⃣ ROTAS MISTAS (Opcional)
129
+ // ========================================
130
+
131
+ export const mixedRoutes = new Elysia()
132
+ // ✅ Autenticação OPCIONAL - adiciona user se autenticado
133
+ .use(cryptoAuthOptional())
134
+
135
+ // Comportamento diferente se autenticado
136
+ .get('/posts/:id', ({ request, params }) => {
137
+ const user = getCryptoAuthUser(request)
138
+ const isAdmin = isCryptoAuthAdmin(request)
139
+
140
+ return {
141
+ post: {
142
+ id: params.id,
143
+ title: 'Título do Post',
144
+ // Mostra conteúdo completo apenas se autenticado
145
+ content: user ? 'Conteúdo completo do post...' : 'Prévia...',
146
+ author: 'João'
147
+ },
148
+ viewer: user ? {
149
+ publicKey: user.publicKey.substring(0, 16) + '...',
150
+ canEdit: isAdmin,
151
+ canComment: true
152
+ } : {
153
+ canEdit: false,
154
+ canComment: false
155
+ }
156
+ }
157
+ })
158
+
159
+ .get('/posts', ({ request }) => {
160
+ const user = getCryptoAuthUser(request)
161
+
162
+ return {
163
+ posts: [
164
+ { id: 1, title: 'Post 1' },
165
+ { id: 2, title: 'Post 2' }
166
+ ],
167
+ authenticated: !!user
168
+ }
169
+ })
170
+
171
+ // ========================================
172
+ // 5️⃣ ROTAS COM VERIFICAÇÃO MANUAL
173
+ // ========================================
174
+
175
+ export const customRoutes = new Elysia()
176
+ .use(cryptoAuthRequired())
177
+
178
+ .get('/posts/:id/edit', ({ request, params, set }) => {
179
+ const user = getCryptoAuthUser(request)!
180
+
181
+ // Verificação customizada - apenas autor ou admin
182
+ const post = { id: params.id, authorKey: 'abc123...' } // Buscar do DB
183
+
184
+ const canEdit = user.isAdmin || user.publicKey === post.authorKey
185
+
186
+ if (!canEdit) {
187
+ set.status = 403
188
+ return {
189
+ error: 'Apenas o autor ou admin podem editar este post'
190
+ }
191
+ }
192
+
193
+ return {
194
+ post,
195
+ canEdit: true
196
+ }
197
+ })
198
+
199
+ // ========================================
200
+ // 6️⃣ COMBINANDO MÚLTIPLOS MIDDLEWARES
201
+ // ========================================
202
+
203
+ export const combinedRoutes = new Elysia({ prefix: '/api/v1' })
204
+ // Primeiro grupo - rotas públicas
205
+ .get('/health', () => ({ status: 'ok' }))
206
+
207
+ .get('/posts', () => ({
208
+ posts: [/* ... */]
209
+ }))
210
+
211
+ // Segundo grupo - rotas protegidas
212
+ .group('/users', (app) => app
213
+ .use(cryptoAuthRequired())
214
+ .get('/', () => ({ users: [] }))
215
+ .post('/', ({ body }) => ({ created: body }))
216
+ )
217
+
218
+ // Terceiro grupo - rotas admin
219
+ .group('/admin', (app) => app
220
+ .use(cryptoAuthAdmin())
221
+ .get('/stats', () => ({ stats: {} }))
222
+ .delete('/users/:id', ({ params }) => ({ deleted: params.id }))
223
+ )
224
+
225
+ // ========================================
226
+ // 7️⃣ EXPORTAR TODAS AS ROTAS
227
+ // ========================================
228
+
229
+ export const allExampleRoutes = new Elysia()
230
+ .use(protectedRoutes)
231
+ .use(adminRoutes)
232
+ .use(writeRoutes)
233
+ .use(mixedRoutes)
234
+ .use(customRoutes)
235
+ .use(combinedRoutes)
@@ -0,0 +1,161 @@
1
+ /**
2
+ * 🎓 EXEMPLO PRÁTICO: Como criar rotas com Crypto-Auth
3
+ *
4
+ * Este arquivo demonstra como um desenvolvedor cria rotas usando
5
+ * o sistema de autenticação crypto-auth do FluxStack.
6
+ */
7
+
8
+ import { Elysia, t } from 'elysia'
9
+ import {
10
+ cryptoAuthRequired,
11
+ cryptoAuthAdmin,
12
+ cryptoAuthOptional,
13
+ getCryptoAuthUser
14
+ } from '@/plugins/crypto-auth/server'
15
+
16
+ // Mock database (simulação)
17
+ const posts = [
18
+ { id: 1, title: 'Post Público 1', content: 'Conteúdo aberto', public: true },
19
+ { id: 2, title: 'Post Público 2', content: 'Conteúdo aberto', public: true }
20
+ ]
21
+
22
+ export const exemploPostsRoutes = new Elysia({ prefix: '/exemplo-posts' })
23
+
24
+ // ========================================
25
+ // 🌐 ROTA PÚBLICA - Qualquer um acessa
26
+ // ========================================
27
+ .get('/', () => {
28
+ return {
29
+ success: true,
30
+ message: 'Lista pública de posts',
31
+ posts: posts.filter(p => p.public)
32
+ }
33
+ })
34
+
35
+ // ========================================
36
+ // 🌓 ROTA COM AUTH OPCIONAL
37
+ // Funciona com ou sem autenticação
38
+ // ========================================
39
+ .guard({}, (app) =>
40
+ app.use(cryptoAuthOptional())
41
+
42
+ .get('/:id', ({ request, params }) => {
43
+ const user = getCryptoAuthUser(request)
44
+ const isAuthenticated = !!user
45
+ const post = posts.find(p => p.id === parseInt(params.id))
46
+
47
+ if (!post) {
48
+ return { success: false, error: 'Post não encontrado' }
49
+ }
50
+
51
+ return {
52
+ success: true,
53
+ post: {
54
+ ...post,
55
+ // ✅ Conteúdo extra apenas para autenticados
56
+ premiumContent: isAuthenticated
57
+ ? 'Conteúdo premium exclusivo para usuários autenticados!'
58
+ : null,
59
+ viewer: isAuthenticated
60
+ ? `Autenticado: ${user.publicKey.substring(0, 8)}...`
61
+ : 'Visitante anônimo'
62
+ }
63
+ }
64
+ })
65
+ )
66
+
67
+ // ========================================
68
+ // 🔒 ROTAS PROTEGIDAS - Requer autenticação
69
+ // ========================================
70
+ .guard({}, (app) =>
71
+ app.use(cryptoAuthRequired())
72
+
73
+ // GET /api/exemplo-posts/meus-posts
74
+ .get('/meus-posts', ({ request }) => {
75
+ const user = getCryptoAuthUser(request)!
76
+
77
+ return {
78
+ success: true,
79
+ message: `Posts criados por você`,
80
+ user: {
81
+ publicKey: user.publicKey.substring(0, 16) + '...',
82
+ isAdmin: user.isAdmin
83
+ },
84
+ posts: [
85
+ {
86
+ id: 999,
87
+ title: 'Meu Post Privado',
88
+ content: 'Só eu posso ver',
89
+ author: user.publicKey
90
+ }
91
+ ]
92
+ }
93
+ })
94
+
95
+ // POST /api/exemplo-posts/criar
96
+ .post('/criar', ({ request, body }) => {
97
+ const user = getCryptoAuthUser(request)!
98
+ const { title, content } = body as { title: string; content: string }
99
+
100
+ const newPost = {
101
+ id: Date.now(),
102
+ title,
103
+ content,
104
+ author: user.publicKey,
105
+ createdAt: new Date().toISOString(),
106
+ public: false
107
+ }
108
+
109
+ posts.push(newPost)
110
+
111
+ return {
112
+ success: true,
113
+ message: 'Post criado com sucesso!',
114
+ post: newPost
115
+ }
116
+ }, {
117
+ body: t.Object({
118
+ title: t.String({ minLength: 3 }),
119
+ content: t.String({ minLength: 10 })
120
+ })
121
+ })
122
+ )
123
+
124
+ // ========================================
125
+ // 👑 ROTAS ADMIN - Apenas administradores
126
+ // ========================================
127
+ .guard({}, (app) =>
128
+ app.use(cryptoAuthAdmin())
129
+
130
+ // GET /api/exemplo-posts/admin/todos
131
+ .get('/admin/todos', ({ request }) => {
132
+ const user = getCryptoAuthUser(request)!
133
+
134
+ return {
135
+ success: true,
136
+ message: 'Painel administrativo',
137
+ admin: user.publicKey.substring(0, 8) + '...',
138
+ totalPosts: posts.length,
139
+ posts: posts // Admin vê tudo
140
+ }
141
+ })
142
+
143
+ // DELETE /api/exemplo-posts/admin/:id
144
+ .delete('/admin/:id', ({ request, params }) => {
145
+ const user = getCryptoAuthUser(request)!
146
+ const postIndex = posts.findIndex(p => p.id === parseInt(params.id))
147
+
148
+ if (postIndex === -1) {
149
+ return { success: false, error: 'Post não encontrado' }
150
+ }
151
+
152
+ const deletedPost = posts.splice(postIndex, 1)[0]
153
+
154
+ return {
155
+ success: true,
156
+ message: `Post "${deletedPost.title}" deletado pelo admin`,
157
+ deletedBy: user.publicKey.substring(0, 8) + '...',
158
+ deletedPost
159
+ }
160
+ })
161
+ )
@@ -2,6 +2,8 @@ import { Elysia, t } from "elysia"
2
2
  import { usersRoutes } from "./users.routes"
3
3
  import { uploadRoutes } from "./upload"
4
4
  import { configRoutes } from "./config"
5
+ import { cryptoAuthDemoRoutes } from "./crypto-auth-demo.routes"
6
+ import { exemploPostsRoutes } from "./exemplo-posts.routes"
5
7
 
6
8
  export const apiRoutes = new Elysia({ prefix: "/api" })
7
9
  .get("/", () => ({ message: "🔥 Hot Reload funcionando! FluxStack API v1.4.0 ⚡" }), {
@@ -36,4 +38,6 @@ export const apiRoutes = new Elysia({ prefix: "/api" })
36
38
  })
37
39
  .use(usersRoutes)
38
40
  .use(uploadRoutes)
39
- .use(configRoutes)
41
+ .use(configRoutes)
42
+ .use(cryptoAuthDemoRoutes)
43
+ .use(exemploPostsRoutes) // ✅ Exemplo de rotas com crypto-auth
package/config/index.ts CHANGED
@@ -27,6 +27,9 @@ export { buildConfig } from './build.config'
27
27
  export { appRuntimeConfig } from './runtime.config'
28
28
  export { systemConfig, systemRuntimeInfo } from './system.config'
29
29
 
30
+ // Plugin configs (re-exported for convenience)
31
+ export { cryptoAuthConfig } from '../plugins/crypto-auth/config'
32
+
30
33
  // Re-export types
31
34
  export type { AppConfig } from './app.config'
32
35
  export type { DatabaseConfig } from './database.config'
@@ -41,6 +44,9 @@ export type {
41
44
  RedisConfig
42
45
  } from './services.config'
43
46
 
47
+ // Plugin types
48
+ export type { CryptoAuthConfig } from '../plugins/crypto-auth/config'
49
+
44
50
  /**
45
51
  * All configs in one object
46
52
  */
@@ -52,6 +58,7 @@ import { loggerConfig } from './logger.config'
52
58
  import { buildConfig } from './build.config'
53
59
  import { appRuntimeConfig } from './runtime.config'
54
60
  import { systemConfig, systemRuntimeInfo } from './system.config'
61
+ import { cryptoAuthConfig } from '../plugins/crypto-auth/config'
55
62
 
56
63
  export const config = {
57
64
  app: appConfig,
@@ -62,7 +69,8 @@ export const config = {
62
69
  build: buildConfig,
63
70
  runtime: appRuntimeConfig,
64
71
  system: systemConfig,
65
- systemRuntime: systemRuntimeInfo
72
+ systemRuntime: systemRuntimeInfo,
73
+ cryptoAuth: cryptoAuthConfig
66
74
  }
67
75
 
68
76
  export default config