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
@@ -3,7 +3,7 @@
3
3
  * Gera rotas protegidas automaticamente
4
4
  */
5
5
 
6
- import type { CliCommand, CliContext } from '@/core/plugins/types'
6
+ import type { CliCommand, CliContext } from '@core/plugins/types'
7
7
  import { writeFileSync, existsSync, mkdirSync } from 'fs'
8
8
  import { join } from 'path'
9
9
 
@@ -1,302 +1,302 @@
1
- /**
2
- * Cliente de Autenticação Criptográfica
3
- * Sistema baseado em assinatura Ed25519 SEM sessões no servidor
4
- *
5
- * Funcionamento:
6
- * 1. Cliente gera par de chaves Ed25519 localmente
7
- * 2. Chave privada NUNCA sai do navegador
8
- * 3. Cada requisição é assinada automaticamente
9
- * 4. Servidor valida assinatura usando chave pública recebida
10
- */
11
-
12
- import { ed25519 } from '@noble/curves/ed25519'
13
- import { sha256 } from '@noble/hashes/sha256'
14
- import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
15
-
16
- export interface KeyPair {
17
- publicKey: string
18
- privateKey: string
19
- createdAt: Date
20
- }
21
-
22
- export interface AuthConfig {
23
- storage?: 'localStorage' | 'sessionStorage' | 'memory'
24
- autoInit?: boolean
25
- }
26
-
27
- export interface SignedRequestOptions extends RequestInit {
28
- skipAuth?: boolean
29
- }
30
-
31
- export class CryptoAuthClient {
32
- private keys: KeyPair | null = null
33
- private config: AuthConfig
34
- private storage: Storage | Map<string, string>
35
- private readonly STORAGE_KEY = 'fluxstack_crypto_keys'
36
-
37
- constructor(config: AuthConfig = {}) {
38
- this.config = {
39
- storage: 'localStorage',
40
- autoInit: true,
41
- ...config
42
- }
43
-
44
- // Configurar storage
45
- if (this.config.storage === 'localStorage' && typeof localStorage !== 'undefined') {
46
- this.storage = localStorage
47
- } else if (this.config.storage === 'sessionStorage' && typeof sessionStorage !== 'undefined') {
48
- this.storage = sessionStorage
49
- } else {
50
- this.storage = new Map<string, string>()
51
- }
52
-
53
- // Auto-inicializar se configurado
54
- if (this.config.autoInit) {
55
- this.initialize()
56
- }
57
- }
58
-
59
- /**
60
- * Inicializar (gerar ou carregar chaves)
61
- */
62
- initialize(): KeyPair {
63
- // Tentar carregar chaves existentes
64
- const existingKeys = this.loadKeys()
65
- if (existingKeys) {
66
- this.keys = existingKeys
67
- return existingKeys
68
- }
69
-
70
- // Criar novo par de chaves
71
- return this.createNewKeys()
72
- }
73
-
74
- /**
75
- * Criar novo par de chaves
76
- * NUNCA envia chave privada ao servidor!
77
- */
78
- createNewKeys(): KeyPair {
79
- // Gerar par de chaves Ed25519
80
- const privateKey = ed25519.utils.randomPrivateKey()
81
- const publicKey = ed25519.getPublicKey(privateKey)
82
-
83
- const keys: KeyPair = {
84
- publicKey: bytesToHex(publicKey),
85
- privateKey: bytesToHex(privateKey),
86
- createdAt: new Date()
87
- }
88
-
89
- this.keys = keys
90
- this.saveKeys(keys)
91
-
92
- return keys
93
- }
94
-
95
- /**
96
- * Fazer requisição autenticada com assinatura
97
- */
98
- async fetch(url: string, options: SignedRequestOptions = {}): Promise<Response> {
99
- const { skipAuth = false, ...fetchOptions } = options
100
-
101
- if (skipAuth) {
102
- return fetch(url, fetchOptions)
103
- }
104
-
105
- if (!this.keys) {
106
- this.initialize()
107
- }
108
-
109
- if (!this.keys) {
110
- throw new Error('Chaves não inicializadas')
111
- }
112
-
113
- // Preparar dados de autenticação
114
- const timestamp = Date.now()
115
- const nonce = this.generateNonce()
116
- const message = this.buildMessage(fetchOptions.method || 'GET', url, fetchOptions.body)
117
- const signature = this.signMessage(message, timestamp, nonce)
118
-
119
- // Adicionar headers de autenticação
120
- const headers = {
121
- 'Content-Type': 'application/json',
122
- ...fetchOptions.headers,
123
- 'x-public-key': this.keys.publicKey,
124
- 'x-timestamp': timestamp.toString(),
125
- 'x-nonce': nonce,
126
- 'x-signature': signature
127
- }
128
-
129
- return fetch(url, {
130
- ...fetchOptions,
131
- headers
132
- })
133
- }
134
-
135
- /**
136
- * Obter chaves atuais
137
- */
138
- getKeys(): KeyPair | null {
139
- return this.keys
140
- }
141
-
142
- /**
143
- * Verificar se tem chaves
144
- */
145
- isInitialized(): boolean {
146
- return this.keys !== null
147
- }
148
-
149
- /**
150
- * Limpar chaves (logout)
151
- */
152
- clearKeys(): void {
153
- this.keys = null
154
- if (this.storage instanceof Map) {
155
- this.storage.delete(this.STORAGE_KEY)
156
- } else {
157
- this.storage.removeItem(this.STORAGE_KEY)
158
- }
159
- }
160
-
161
- /**
162
- * Importar chave privada existente
163
- * @param privateKeyHex - Chave privada em formato hexadecimal (64 caracteres)
164
- * @returns KeyPair com as chaves importadas
165
- * @throws Error se a chave privada for inválida
166
- */
167
- importPrivateKey(privateKeyHex: string): KeyPair {
168
- // Validar formato
169
- if (!/^[a-fA-F0-9]{64}$/.test(privateKeyHex)) {
170
- throw new Error('Chave privada inválida. Deve ter 64 caracteres hexadecimais.')
171
- }
172
-
173
- try {
174
- // Converter hex para bytes
175
- const privateKeyBytes = hexToBytes(privateKeyHex)
176
-
177
- // Derivar chave pública da privada
178
- const publicKeyBytes = ed25519.getPublicKey(privateKeyBytes)
179
-
180
- const keys: KeyPair = {
181
- publicKey: bytesToHex(publicKeyBytes),
182
- privateKey: privateKeyHex.toLowerCase(),
183
- createdAt: new Date()
184
- }
185
-
186
- this.keys = keys
187
- this.saveKeys(keys)
188
-
189
- return keys
190
- } catch (error) {
191
- throw new Error('Erro ao importar chave privada: ' + (error as Error).message)
192
- }
193
- }
194
-
195
- /**
196
- * Exportar chave privada (para backup)
197
- * @returns Chave privada em formato hexadecimal
198
- * @throws Error se não houver chaves inicializadas
199
- */
200
- exportPrivateKey(): string {
201
- if (!this.keys) {
202
- throw new Error('Nenhuma chave inicializada para exportar')
203
- }
204
-
205
- return this.keys.privateKey
206
- }
207
-
208
- /**
209
- * Assinar mensagem
210
- */
211
- private signMessage(message: string, timestamp: number, nonce: string): string {
212
- if (!this.keys) {
213
- throw new Error('Chaves não inicializadas')
214
- }
215
-
216
- // Construir mensagem completa: publicKey:timestamp:nonce:message
217
- const fullMessage = `${this.keys.publicKey}:${timestamp}:${nonce}:${message}`
218
- const messageHash = sha256(new TextEncoder().encode(fullMessage))
219
-
220
- const privateKeyBytes = hexToBytes(this.keys.privateKey)
221
- const signature = ed25519.sign(messageHash, privateKeyBytes)
222
-
223
- return bytesToHex(signature)
224
- }
225
-
226
- /**
227
- * Construir mensagem para assinatura
228
- */
229
- private buildMessage(method: string, url: string, body?: BodyInit | null): string {
230
- let message = `${method}:${url}`
231
-
232
- if (body) {
233
- if (typeof body === 'string') {
234
- message += `:${body}`
235
- } else {
236
- message += `:${JSON.stringify(body)}`
237
- }
238
- }
239
-
240
- return message
241
- }
242
-
243
- /**
244
- * Gerar nonce aleatório
245
- */
246
- private generateNonce(): string {
247
- const bytes = new Uint8Array(16)
248
- crypto.getRandomValues(bytes)
249
- return bytesToHex(bytes)
250
- }
251
-
252
- /**
253
- * Carregar chaves do storage
254
- */
255
- private loadKeys(): KeyPair | null {
256
- try {
257
- let data: string | null
258
-
259
- if (this.storage instanceof Map) {
260
- data = this.storage.get(this.STORAGE_KEY) || null
261
- } else {
262
- data = this.storage.getItem(this.STORAGE_KEY)
263
- }
264
-
265
- if (!data) {
266
- return null
267
- }
268
-
269
- const parsed = JSON.parse(data)
270
-
271
- return {
272
- publicKey: parsed.publicKey,
273
- privateKey: parsed.privateKey,
274
- createdAt: new Date(parsed.createdAt)
275
- }
276
- } catch (error) {
277
- console.error('Erro ao carregar chaves:', error)
278
- return null
279
- }
280
- }
281
-
282
- /**
283
- * Salvar chaves no storage
284
- */
285
- private saveKeys(keys: KeyPair): void {
286
- try {
287
- const data = JSON.stringify({
288
- publicKey: keys.publicKey,
289
- privateKey: keys.privateKey,
290
- createdAt: keys.createdAt.toISOString()
291
- })
292
-
293
- if (this.storage instanceof Map) {
294
- this.storage.set(this.STORAGE_KEY, data)
295
- } else {
296
- this.storage.setItem(this.STORAGE_KEY, data)
297
- }
298
- } catch (error) {
299
- console.error('Erro ao salvar chaves:', error)
300
- }
301
- }
302
- }
1
+ /**
2
+ * Cliente de Autenticação Criptográfica
3
+ * Sistema baseado em assinatura Ed25519 SEM sessões no servidor
4
+ *
5
+ * Funcionamento:
6
+ * 1. Cliente gera par de chaves Ed25519 localmente
7
+ * 2. Chave privada NUNCA sai do navegador
8
+ * 3. Cada requisição é assinada automaticamente
9
+ * 4. Servidor valida assinatura usando chave pública recebida
10
+ */
11
+
12
+ import { ed25519 } from '@noble/curves/ed25519'
13
+ import { sha256 } from '@noble/hashes/sha256'
14
+ import { bytesToHex, hexToBytes } from '@noble/hashes/utils'
15
+
16
+ export interface KeyPair {
17
+ publicKey: string
18
+ privateKey: string
19
+ createdAt: Date
20
+ }
21
+
22
+ export interface AuthConfig {
23
+ storage?: 'localStorage' | 'sessionStorage' | 'memory'
24
+ autoInit?: boolean
25
+ }
26
+
27
+ export interface SignedRequestOptions extends RequestInit {
28
+ skipAuth?: boolean
29
+ }
30
+
31
+ export class CryptoAuthClient {
32
+ private keys: KeyPair | null = null
33
+ private config: AuthConfig
34
+ private storage: Storage | Map<string, string>
35
+ private readonly STORAGE_KEY = 'fluxstack_crypto_keys'
36
+
37
+ constructor(config: AuthConfig = {}) {
38
+ this.config = {
39
+ storage: 'localStorage',
40
+ autoInit: true,
41
+ ...config
42
+ }
43
+
44
+ // Configurar storage
45
+ if (this.config.storage === 'localStorage' && typeof localStorage !== 'undefined') {
46
+ this.storage = localStorage
47
+ } else if (this.config.storage === 'sessionStorage' && typeof sessionStorage !== 'undefined') {
48
+ this.storage = sessionStorage
49
+ } else {
50
+ this.storage = new Map<string, string>()
51
+ }
52
+
53
+ // Auto-inicializar se configurado
54
+ if (this.config.autoInit) {
55
+ this.initialize()
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Inicializar (gerar ou carregar chaves)
61
+ */
62
+ initialize(): KeyPair {
63
+ // Tentar carregar chaves existentes
64
+ const existingKeys = this.loadKeys()
65
+ if (existingKeys) {
66
+ this.keys = existingKeys
67
+ return existingKeys
68
+ }
69
+
70
+ // Criar novo par de chaves
71
+ return this.createNewKeys()
72
+ }
73
+
74
+ /**
75
+ * Criar novo par de chaves
76
+ * NUNCA envia chave privada ao servidor!
77
+ */
78
+ createNewKeys(): KeyPair {
79
+ // Gerar par de chaves Ed25519
80
+ const privateKey = ed25519.utils.randomPrivateKey()
81
+ const publicKey = ed25519.getPublicKey(privateKey)
82
+
83
+ const keys: KeyPair = {
84
+ publicKey: bytesToHex(publicKey),
85
+ privateKey: bytesToHex(privateKey),
86
+ createdAt: new Date()
87
+ }
88
+
89
+ this.keys = keys
90
+ this.saveKeys(keys)
91
+
92
+ return keys
93
+ }
94
+
95
+ /**
96
+ * Fazer requisição autenticada com assinatura
97
+ */
98
+ async fetch(url: string, options: SignedRequestOptions = {}): Promise<Response> {
99
+ const { skipAuth = false, ...fetchOptions } = options
100
+
101
+ if (skipAuth) {
102
+ return fetch(url, fetchOptions)
103
+ }
104
+
105
+ if (!this.keys) {
106
+ this.initialize()
107
+ }
108
+
109
+ if (!this.keys) {
110
+ throw new Error('Chaves não inicializadas')
111
+ }
112
+
113
+ // Preparar dados de autenticação
114
+ const timestamp = Date.now()
115
+ const nonce = this.generateNonce()
116
+ const message = this.buildMessage(fetchOptions.method || 'GET', url, fetchOptions.body)
117
+ const signature = this.signMessage(message, timestamp, nonce)
118
+
119
+ // Adicionar headers de autenticação
120
+ const headers = {
121
+ 'Content-Type': 'application/json',
122
+ ...fetchOptions.headers,
123
+ 'x-public-key': this.keys.publicKey,
124
+ 'x-timestamp': timestamp.toString(),
125
+ 'x-nonce': nonce,
126
+ 'x-signature': signature
127
+ }
128
+
129
+ return fetch(url, {
130
+ ...fetchOptions,
131
+ headers
132
+ })
133
+ }
134
+
135
+ /**
136
+ * Obter chaves atuais
137
+ */
138
+ getKeys(): KeyPair | null {
139
+ return this.keys
140
+ }
141
+
142
+ /**
143
+ * Verificar se tem chaves
144
+ */
145
+ isInitialized(): boolean {
146
+ return this.keys !== null
147
+ }
148
+
149
+ /**
150
+ * Limpar chaves (logout)
151
+ */
152
+ clearKeys(): void {
153
+ this.keys = null
154
+ if (this.storage instanceof Map) {
155
+ this.storage.delete(this.STORAGE_KEY)
156
+ } else {
157
+ this.storage.removeItem(this.STORAGE_KEY)
158
+ }
159
+ }
160
+
161
+ /**
162
+ * Importar chave privada existente
163
+ * @param privateKeyHex - Chave privada em formato hexadecimal (64 caracteres)
164
+ * @returns KeyPair com as chaves importadas
165
+ * @throws Error se a chave privada for inválida
166
+ */
167
+ importPrivateKey(privateKeyHex: string): KeyPair {
168
+ // Validar formato
169
+ if (!/^[a-fA-F0-9]{64}$/.test(privateKeyHex)) {
170
+ throw new Error('Chave privada inválida. Deve ter 64 caracteres hexadecimais.')
171
+ }
172
+
173
+ try {
174
+ // Converter hex para bytes
175
+ const privateKeyBytes = hexToBytes(privateKeyHex)
176
+
177
+ // Derivar chave pública da privada
178
+ const publicKeyBytes = ed25519.getPublicKey(privateKeyBytes)
179
+
180
+ const keys: KeyPair = {
181
+ publicKey: bytesToHex(publicKeyBytes),
182
+ privateKey: privateKeyHex.toLowerCase(),
183
+ createdAt: new Date()
184
+ }
185
+
186
+ this.keys = keys
187
+ this.saveKeys(keys)
188
+
189
+ return keys
190
+ } catch (error) {
191
+ throw new Error('Erro ao importar chave privada: ' + (error as Error).message)
192
+ }
193
+ }
194
+
195
+ /**
196
+ * Exportar chave privada (para backup)
197
+ * @returns Chave privada em formato hexadecimal
198
+ * @throws Error se não houver chaves inicializadas
199
+ */
200
+ exportPrivateKey(): string {
201
+ if (!this.keys) {
202
+ throw new Error('Nenhuma chave inicializada para exportar')
203
+ }
204
+
205
+ return this.keys.privateKey
206
+ }
207
+
208
+ /**
209
+ * Assinar mensagem
210
+ */
211
+ private signMessage(message: string, timestamp: number, nonce: string): string {
212
+ if (!this.keys) {
213
+ throw new Error('Chaves não inicializadas')
214
+ }
215
+
216
+ // Construir mensagem completa: publicKey:timestamp:nonce:message
217
+ const fullMessage = `${this.keys.publicKey}:${timestamp}:${nonce}:${message}`
218
+ const messageHash = sha256(new TextEncoder().encode(fullMessage))
219
+
220
+ const privateKeyBytes = hexToBytes(this.keys.privateKey)
221
+ const signature = ed25519.sign(messageHash, privateKeyBytes)
222
+
223
+ return bytesToHex(signature)
224
+ }
225
+
226
+ /**
227
+ * Construir mensagem para assinatura
228
+ */
229
+ private buildMessage(method: string, url: string, body?: BodyInit | null): string {
230
+ let message = `${method}:${url}`
231
+
232
+ if (body) {
233
+ if (typeof body === 'string') {
234
+ message += `:${body}`
235
+ } else {
236
+ message += `:${JSON.stringify(body)}`
237
+ }
238
+ }
239
+
240
+ return message
241
+ }
242
+
243
+ /**
244
+ * Gerar nonce aleatório
245
+ */
246
+ private generateNonce(): string {
247
+ const bytes = new Uint8Array(16)
248
+ crypto.getRandomValues(bytes)
249
+ return bytesToHex(bytes)
250
+ }
251
+
252
+ /**
253
+ * Carregar chaves do storage
254
+ */
255
+ private loadKeys(): KeyPair | null {
256
+ try {
257
+ let data: string | null
258
+
259
+ if (this.storage instanceof Map) {
260
+ data = this.storage.get(this.STORAGE_KEY) || null
261
+ } else {
262
+ data = this.storage.getItem(this.STORAGE_KEY)
263
+ }
264
+
265
+ if (!data) {
266
+ return null
267
+ }
268
+
269
+ const parsed = JSON.parse(data)
270
+
271
+ return {
272
+ publicKey: parsed.publicKey,
273
+ privateKey: parsed.privateKey,
274
+ createdAt: new Date(parsed.createdAt)
275
+ }
276
+ } catch (error) {
277
+ console.error('Erro ao carregar chaves:', error)
278
+ return null
279
+ }
280
+ }
281
+
282
+ /**
283
+ * Salvar chaves no storage
284
+ */
285
+ private saveKeys(keys: KeyPair): void {
286
+ try {
287
+ const data = JSON.stringify({
288
+ publicKey: keys.publicKey,
289
+ privateKey: keys.privateKey,
290
+ createdAt: keys.createdAt.toISOString()
291
+ })
292
+
293
+ if (this.storage instanceof Map) {
294
+ this.storage.set(this.STORAGE_KEY, data)
295
+ } else {
296
+ this.storage.setItem(this.STORAGE_KEY, data)
297
+ }
298
+ } catch (error) {
299
+ console.error('Erro ao salvar chaves:', error)
300
+ }
301
+ }
302
+ }
@@ -1,12 +1,12 @@
1
- /**
2
- * Exportações dos componentes do cliente
3
- */
4
-
5
- export { LoginButton } from './LoginButton'
6
- export type { LoginButtonProps } from './LoginButton'
7
-
8
- export { AuthProvider, useAuth } from './AuthProvider'
9
- export type { AuthProviderProps, AuthContextValue } from './AuthProvider'
10
-
11
- export { ProtectedRoute, withAuth } from './ProtectedRoute'
1
+ /**
2
+ * Exportações dos componentes do cliente
3
+ */
4
+
5
+ export { LoginButton } from './LoginButton'
6
+ export type { LoginButtonProps } from './LoginButton'
7
+
8
+ export { AuthProvider, useAuth } from './AuthProvider'
9
+ export type { AuthProviderProps, AuthContextValue } from './AuthProvider'
10
+
11
+ export { ProtectedRoute, withAuth } from './ProtectedRoute'
12
12
  export type { ProtectedRouteProps } from './ProtectedRoute'
@@ -1,12 +1,12 @@
1
- /**
2
- * Exportações principais do cliente de autenticação
3
- */
4
-
5
- export { CryptoAuthClient } from './CryptoAuthClient'
6
- export type { KeyPair, AuthConfig, SignedRequestOptions } from './CryptoAuthClient'
7
-
8
- // Componentes React
9
- export * from './components'
10
-
11
- // Re-exportar para compatibilidade
1
+ /**
2
+ * Exportações principais do cliente de autenticação
3
+ */
4
+
5
+ export { CryptoAuthClient } from './CryptoAuthClient'
6
+ export type { KeyPair, AuthConfig, SignedRequestOptions } from './CryptoAuthClient'
7
+
8
+ // Componentes React
9
+ export * from './components'
10
+
11
+ // Re-exportar para compatibilidade
12
12
  export { CryptoAuthClient as default } from './CryptoAuthClient'
@@ -3,7 +3,7 @@
3
3
  * Declarative config using FluxStack config system
4
4
  */
5
5
 
6
- import { defineConfig, config } from '@/core/utils/config-schema'
6
+ import { defineConfig, config } from '@core/utils/config-schema'
7
7
 
8
8
  const cryptoAuthConfigSchema = {
9
9
  // Enable/disable plugin