create-fluxstack 1.18.0 → 1.19.0

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 (54) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/app/client/src/App.tsx +7 -7
  3. package/app/client/src/components/AppLayout.tsx +60 -23
  4. package/app/client/src/components/ColorWheel.tsx +195 -0
  5. package/app/client/src/components/DemoPage.tsx +5 -3
  6. package/app/client/src/components/LiveUploadWidget.tsx +1 -1
  7. package/app/client/src/components/ThemePicker.tsx +307 -0
  8. package/app/client/src/config/theme.config.ts +127 -0
  9. package/app/client/src/hooks/useThemeClock.ts +66 -0
  10. package/app/client/src/index.css +193 -0
  11. package/app/client/src/lib/theme-clock.ts +201 -0
  12. package/app/client/src/live/AuthDemo.tsx +9 -9
  13. package/app/client/src/live/CounterDemo.tsx +10 -10
  14. package/app/client/src/live/FormDemo.tsx +8 -8
  15. package/app/client/src/live/PingPongDemo.tsx +10 -10
  16. package/app/client/src/live/RoomChatDemo.tsx +10 -10
  17. package/app/client/src/live/SharedCounterDemo.tsx +5 -5
  18. package/app/client/src/pages/ApiTestPage.tsx +5 -5
  19. package/app/client/src/pages/HomePage.tsx +12 -12
  20. package/app/server/index.ts +8 -0
  21. package/app/server/live/auto-generated-components.ts +1 -1
  22. package/app/server/live/rooms/ChatRoom.ts +13 -8
  23. package/app/server/routes/index.ts +20 -10
  24. package/core/build/index.ts +1 -1
  25. package/core/cli/command-registry.ts +1 -1
  26. package/core/cli/commands/build.ts +25 -6
  27. package/core/cli/commands/plugin-deps.ts +1 -2
  28. package/core/cli/generators/plugin.ts +433 -581
  29. package/core/framework/server.ts +34 -8
  30. package/core/index.ts +6 -5
  31. package/core/plugins/index.ts +71 -199
  32. package/core/plugins/types.ts +76 -461
  33. package/core/server/index.ts +1 -1
  34. package/core/utils/logger/startup-banner.ts +26 -4
  35. package/core/utils/version.ts +6 -6
  36. package/create-fluxstack.ts +216 -107
  37. package/package.json +108 -107
  38. package/tsconfig.json +2 -1
  39. package/app/client/.live-stubs/LiveAdminPanel.js +0 -15
  40. package/app/client/.live-stubs/LiveCounter.js +0 -9
  41. package/app/client/.live-stubs/LiveForm.js +0 -11
  42. package/app/client/.live-stubs/LiveLocalCounter.js +0 -8
  43. package/app/client/.live-stubs/LivePingPong.js +0 -10
  44. package/app/client/.live-stubs/LiveRoomChat.js +0 -11
  45. package/app/client/.live-stubs/LiveSharedCounter.js +0 -10
  46. package/app/client/.live-stubs/LiveUpload.js +0 -15
  47. package/core/plugins/config.ts +0 -356
  48. package/core/plugins/dependency-manager.ts +0 -481
  49. package/core/plugins/discovery.ts +0 -379
  50. package/core/plugins/executor.ts +0 -353
  51. package/core/plugins/manager.ts +0 -645
  52. package/core/plugins/module-resolver.ts +0 -227
  53. package/core/plugins/registry.ts +0 -913
  54. package/vitest.config.live.ts +0 -69
@@ -1,481 +0,0 @@
1
- /**
2
- * Gerenciador de Dependências de Plugins
3
- * Resolve e instala dependências de plugins automaticamente
4
- */
5
-
6
- import { existsSync, readFileSync, writeFileSync } from 'fs'
7
- import { join, resolve } from 'path'
8
- import { execSync } from 'child_process'
9
- import type { Logger } from '@core/utils/logger'
10
-
11
- export interface PluginDependency {
12
- name: string
13
- version: string
14
- type: 'dependency' | 'devDependency' | 'peerDependency'
15
- optional?: boolean
16
- }
17
-
18
- export interface DependencyResolution {
19
- plugin: string
20
- dependencies: PluginDependency[]
21
- conflicts: DependencyConflict[]
22
- resolved: boolean
23
- }
24
-
25
- export interface DependencyConflict {
26
- package: string
27
- versions: Array<{
28
- plugin: string
29
- version: string
30
- }>
31
- resolution?: string
32
- }
33
-
34
- export interface DependencyManagerConfig {
35
- logger?: Logger
36
- autoInstall?: boolean
37
- packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun'
38
- workspaceRoot?: string
39
- }
40
-
41
- export class PluginDependencyManager {
42
- private logger?: Logger
43
- private config: DependencyManagerConfig
44
- private installedDependencies: Map<string, string> = new Map()
45
- private pluginDependencies: Map<string, PluginDependency[]> = new Map()
46
-
47
- constructor(config: DependencyManagerConfig = {}) {
48
- this.config = {
49
- autoInstall: true,
50
- packageManager: 'bun',
51
- workspaceRoot: process.cwd(),
52
- ...config
53
- }
54
- this.logger = config.logger
55
-
56
- this.loadInstalledDependencies()
57
- }
58
-
59
- /**
60
- * Registrar dependências de um plugin
61
- */
62
- registerPluginDependencies(pluginName: string, dependencies: PluginDependency[]): void {
63
- this.pluginDependencies.set(pluginName, dependencies)
64
- this.logger?.debug(`Dependências registradas para plugin '${pluginName}'`, {
65
- plugin: pluginName,
66
- dependencies: dependencies.length
67
- })
68
- }
69
-
70
- /**
71
- * Resolver dependências de um plugin a partir do package.json
72
- */
73
- async resolvePluginDependencies(pluginPath: string): Promise<DependencyResolution> {
74
- const pluginName = this.getPluginNameFromPath(pluginPath)
75
- const packageJsonPath = join(pluginPath, 'package.json')
76
-
77
- if (!existsSync(packageJsonPath)) {
78
- return {
79
- plugin: pluginName,
80
- dependencies: [],
81
- conflicts: [],
82
- resolved: true
83
- }
84
- }
85
-
86
- try {
87
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
88
- const dependencies: PluginDependency[] = []
89
-
90
- // Processar dependencies
91
- if (packageJson.dependencies) {
92
- for (const [name, version] of Object.entries(packageJson.dependencies)) {
93
- dependencies.push({
94
- name,
95
- version: version as string,
96
- type: 'dependency'
97
- })
98
- }
99
- }
100
-
101
- // Processar peerDependencies
102
- if (packageJson.peerDependencies) {
103
- for (const [name, version] of Object.entries(packageJson.peerDependencies)) {
104
- const isOptional = packageJson.peerDependenciesMeta?.[name]?.optional || false
105
- dependencies.push({
106
- name,
107
- version: version as string,
108
- type: 'peerDependency',
109
- optional: isOptional
110
- })
111
- }
112
- }
113
-
114
- // Registrar dependências
115
- this.registerPluginDependencies(pluginName, dependencies)
116
-
117
- // Detectar conflitos
118
- const conflicts = this.detectConflicts(pluginName, dependencies)
119
-
120
- return {
121
- plugin: pluginName,
122
- dependencies,
123
- conflicts,
124
- resolved: conflicts.length === 0
125
- }
126
- } catch (error) {
127
- this.logger?.error(`Erro ao resolver dependências do plugin '${pluginName}'`, { error })
128
- return {
129
- plugin: pluginName,
130
- dependencies: [],
131
- conflicts: [],
132
- resolved: false
133
- }
134
- }
135
- }
136
-
137
- /**
138
- * Instalar dependências de plugins
139
- * NOVA ESTRATÉGIA: Instala no node_modules local do plugin primeiro,
140
- * com fallback para o projeto principal
141
- */
142
- async installPluginDependencies(resolutions: DependencyResolution[]): Promise<void> {
143
- if (!this.config.autoInstall) {
144
- this.logger?.debug('Auto-instalação desabilitada, pulando instalação de dependências')
145
- return
146
- }
147
-
148
- // Instalar dependências para cada plugin individualmente
149
- for (const resolution of resolutions) {
150
- if (resolution.dependencies.length === 0) continue
151
-
152
- const pluginPath = this.findPluginDirectory(resolution.plugin)
153
- if (!pluginPath) {
154
- this.logger?.warn(`Não foi possível encontrar diretório do plugin '${resolution.plugin}'`)
155
- continue
156
- }
157
-
158
- this.logger?.debug(`📦 Instalando dependências localmente para plugin '${resolution.plugin}'`, {
159
- plugin: resolution.plugin,
160
- path: pluginPath,
161
- dependencies: resolution.dependencies.length
162
- })
163
-
164
- try {
165
- // Instalar APENAS no node_modules local do plugin
166
- await this.installPluginDependenciesLocally(pluginPath, resolution.dependencies)
167
-
168
- this.logger?.debug(`✅ Dependências do plugin '${resolution.plugin}' instaladas localmente`)
169
- } catch (error) {
170
- this.logger?.error(`❌ Erro ao instalar dependências do plugin '${resolution.plugin}'`, { error })
171
- // Continuar com outros plugins
172
- }
173
- }
174
- }
175
-
176
- /**
177
- * Instalar dependências no diretório local do plugin
178
- */
179
- async installPluginDependenciesLocally(pluginPath: string, dependencies: PluginDependency[]): Promise<void> {
180
- if (dependencies.length === 0) return
181
-
182
- const regularDeps = dependencies.filter(d => d.type === 'dependency')
183
- const peerDeps = dependencies.filter(d => d.type === 'peerDependency' && !d.optional)
184
-
185
- const allDeps = [...regularDeps, ...peerDeps]
186
- if (allDeps.length === 0) return
187
-
188
- // Verificar quais dependências já estão instaladas localmente
189
- const toInstall = allDeps.filter(dep => {
190
- const depPath = join(pluginPath, 'node_modules', dep.name, 'package.json')
191
- if (!existsSync(depPath)) {
192
- return true // Precisa instalar
193
- }
194
-
195
- try {
196
- const installedPkg = JSON.parse(readFileSync(depPath, 'utf-8'))
197
- const installedVersion = installedPkg.version
198
-
199
- // Verificar se a versão é compatível
200
- if (!this.isVersionCompatible(installedVersion, dep.version)) {
201
- this.logger?.debug(`📦 Dependência '${dep.name}' está desatualizada (${installedVersion} → ${dep.version})`)
202
- return true // Precisa atualizar
203
- }
204
-
205
- return false // Já está instalado corretamente
206
- } catch (error) {
207
- return true // Erro ao ler, melhor reinstalar
208
- }
209
- })
210
-
211
- if (toInstall.length === 0) {
212
- this.logger?.debug(`✅ Todas as dependências do plugin já estão instaladas`)
213
- return
214
- }
215
-
216
- const packages = toInstall.map(d => `${d.name}@${d.version}`).join(' ')
217
- const command = this.getInstallCommand(packages, false)
218
-
219
- this.logger?.debug(`🔧 Instalando ${toInstall.length} dependência(s): ${command}`, { cwd: pluginPath })
220
-
221
- try {
222
- execSync(command, {
223
- cwd: pluginPath,
224
- stdio: 'inherit'
225
- })
226
- this.logger?.debug(`✅ Pacotes instalados localmente em ${pluginPath}`)
227
- } catch (error) {
228
- this.logger?.error(`❌ Falha ao instalar dependências localmente`, { error, pluginPath })
229
- throw error
230
- }
231
- }
232
-
233
- /**
234
- * Instalar dependências diretamente em um path específico
235
- */
236
- async installDependenciesInPath(pluginPath: string, dependencies: Record<string, string>): Promise<void> {
237
- if (!this.config.autoInstall) {
238
- this.logger?.debug('Auto-instalação desabilitada')
239
- return
240
- }
241
-
242
- if (Object.keys(dependencies).length === 0) {
243
- return
244
- }
245
-
246
- const pluginDeps: PluginDependency[] = Object.entries(dependencies).map(([name, version]) => ({
247
- name,
248
- version,
249
- type: 'dependency'
250
- }))
251
-
252
- this.logger?.debug(`📦 Instalando ${pluginDeps.length} dependência(s) em ${pluginPath}`)
253
-
254
- try {
255
- await this.installPluginDependenciesLocally(pluginPath, pluginDeps)
256
- this.logger?.debug(`✅ Dependências instaladas com sucesso em ${pluginPath}`)
257
- } catch (error) {
258
- this.logger?.error(`❌ Erro ao instalar dependências em ${pluginPath}`, { error })
259
- throw error
260
- }
261
- }
262
-
263
- /**
264
- * Encontrar diretório de um plugin pelo nome
265
- */
266
- private findPluginDirectory(pluginName: string): string | null {
267
- const possiblePaths = [
268
- `plugins/${pluginName}`,
269
- `core/plugins/built-in/${pluginName}`
270
- ]
271
-
272
- for (const path of possiblePaths) {
273
- if (existsSync(path)) {
274
- return resolve(path)
275
- }
276
- }
277
-
278
- return null
279
- }
280
-
281
- /**
282
- * Detectar conflitos de versão
283
- */
284
- private detectConflicts(pluginName: string, dependencies: PluginDependency[]): DependencyConflict[] {
285
- const conflicts: DependencyConflict[] = []
286
-
287
- for (const dep of dependencies) {
288
- const existingVersions: Array<{ plugin: string; version: string }> = []
289
-
290
- // Verificar se outros plugins já declararam esta dependência
291
- for (const [otherPlugin, otherDeps] of this.pluginDependencies.entries()) {
292
- if (otherPlugin === pluginName) continue
293
-
294
- const conflictingDep = otherDeps.find(d => d.name === dep.name)
295
- if (conflictingDep && !this.isVersionCompatible(conflictingDep.version, dep.version)) {
296
- existingVersions.push({
297
- plugin: otherPlugin,
298
- version: conflictingDep.version
299
- })
300
- }
301
- }
302
-
303
- if (existingVersions.length > 0) {
304
- existingVersions.push({
305
- plugin: pluginName,
306
- version: dep.version
307
- })
308
-
309
- conflicts.push({
310
- package: dep.name,
311
- versions: existingVersions
312
- })
313
- }
314
- }
315
-
316
- return conflicts
317
- }
318
-
319
- /**
320
- * Resolver conflitos de dependências
321
- */
322
- private async resolveConflicts(conflicts: DependencyConflict[]): Promise<void> {
323
- this.logger?.warn(`Detectados ${conflicts.length} conflitos de dependências`, {
324
- conflicts: conflicts.map(c => ({
325
- package: c.package,
326
- versions: c.versions.length
327
- }))
328
- })
329
-
330
- for (const conflict of conflicts) {
331
- // Estratégia simples: usar a versão mais alta
332
- const sortedVersions = conflict.versions.sort((a, b) => {
333
- return this.compareVersions(b.version, a.version)
334
- })
335
-
336
- const resolution = sortedVersions[0].version
337
- conflict.resolution = resolution
338
-
339
- this.logger?.debug(`Conflito resolvido para '${conflict.package}': usando versão ${resolution}`, {
340
- package: conflict.package,
341
- resolution,
342
- conflictingVersions: conflict.versions
343
- })
344
- }
345
- }
346
-
347
- /**
348
- * Instalar dependências usando o package manager configurado
349
- */
350
- private async installDependencies(dependencies: PluginDependency[]): Promise<void> {
351
- const regularDeps = dependencies.filter(d => d.type === 'dependency')
352
- const peerDeps = dependencies.filter(d => d.type === 'peerDependency' && !d.optional)
353
-
354
- if (regularDeps.length > 0) {
355
- const packages = regularDeps.map(d => `${d.name}@${d.version}`).join(' ')
356
- const command = this.getInstallCommand(packages, false)
357
-
358
- this.logger?.debug(`Executando: ${command}`)
359
- execSync(command, {
360
- cwd: this.config.workspaceRoot,
361
- stdio: 'inherit'
362
- })
363
- }
364
-
365
- if (peerDeps.length > 0) {
366
- const packages = peerDeps.map(d => `${d.name}@${d.version}`).join(' ')
367
- const command = this.getInstallCommand(packages, false) // Peer deps como regulares
368
-
369
- this.logger?.debug(`Executando: ${command}`)
370
- execSync(command, {
371
- cwd: this.config.workspaceRoot,
372
- stdio: 'inherit'
373
- })
374
- }
375
-
376
- // Recarregar dependências instaladas
377
- this.loadInstalledDependencies()
378
- }
379
-
380
- /**
381
- * Obter comando de instalação baseado no package manager
382
- */
383
- private getInstallCommand(packages: string, dev: boolean): string {
384
- const devFlag = dev ? '--save-dev' : ''
385
-
386
- switch (this.config.packageManager) {
387
- case 'npm':
388
- return `npm install ${devFlag} ${packages}`
389
- case 'yarn':
390
- return `yarn add ${dev ? '--dev' : ''} ${packages}`
391
- case 'pnpm':
392
- return `pnpm add ${devFlag} ${packages}`
393
- case 'bun':
394
- return `bun add ${devFlag} ${packages}`
395
- default:
396
- return `npm install ${devFlag} ${packages}`
397
- }
398
- }
399
-
400
- /**
401
- * Carregar dependências já instaladas
402
- */
403
- private loadInstalledDependencies(): void {
404
- const packageJsonPath = join(this.config.workspaceRoot!, 'package.json')
405
-
406
- if (!existsSync(packageJsonPath)) {
407
- return
408
- }
409
-
410
- try {
411
- const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
412
-
413
- // Carregar dependencies
414
- if (packageJson.dependencies) {
415
- for (const [name, version] of Object.entries(packageJson.dependencies)) {
416
- this.installedDependencies.set(name, version as string)
417
- }
418
- }
419
-
420
- // Carregar devDependencies
421
- if (packageJson.devDependencies) {
422
- for (const [name, version] of Object.entries(packageJson.devDependencies)) {
423
- this.installedDependencies.set(name, version as string)
424
- }
425
- }
426
- } catch (error) {
427
- this.logger?.warn('Erro ao carregar package.json principal', { error })
428
- }
429
- }
430
-
431
- /**
432
- * Verificar se versões são compatíveis
433
- */
434
- private isVersionCompatible(installed: string, required: string): boolean {
435
- // Implementação simples - em produção usaria semver
436
- if (required.startsWith('^') || required.startsWith('~')) {
437
- const requiredVersion = required.slice(1)
438
- return this.compareVersions(installed, requiredVersion) >= 0
439
- }
440
-
441
- return installed === required
442
- }
443
-
444
- /**
445
- * Comparar versões (implementação simples)
446
- */
447
- private compareVersions(a: string, b: string): number {
448
- const aParts = a.replace(/[^\d.]/g, '').split('.').map(Number)
449
- const bParts = b.replace(/[^\d.]/g, '').split('.').map(Number)
450
-
451
- for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
452
- const aPart = aParts[i] || 0
453
- const bPart = bParts[i] || 0
454
-
455
- if (aPart > bPart) return 1
456
- if (aPart < bPart) return -1
457
- }
458
-
459
- return 0
460
- }
461
-
462
- /**
463
- * Extrair nome do plugin do caminho
464
- */
465
- private getPluginNameFromPath(pluginPath: string): string {
466
- return pluginPath.split('/').pop() || 'unknown'
467
- }
468
-
469
- /**
470
- * Obter estatísticas de dependências
471
- */
472
- getStats() {
473
- return {
474
- totalPlugins: this.pluginDependencies.size,
475
- totalDependencies: Array.from(this.pluginDependencies.values())
476
- .reduce((sum, deps) => sum + deps.length, 0),
477
- installedDependencies: this.installedDependencies.size,
478
- packageManager: this.config.packageManager
479
- }
480
- }
481
- }